Я только что немного исследовал эти (совершенно) новые функции, и мне интересно, почему Комитет С++ решил ввести для них один и тот же синтаксис? Похоже, разработчикам не нужно тратить время, чтобы понять, как это работает, и одно решение позволяет подумать о дальнейших проблемах. В моем случае это началось с проблемы, которая может быть упрощена до этого:
#include <iostream>
template <typename T>
void f(T& a)
{
std::cout << "f(T& a) for lvalues\n";
}
template <typename T>
void f(T&& a)
{
std::cout << "f(T&& a) for rvalues\n";
}
int main()
{
int a;
f(a);
f(int());
return 0;
}
Я скомпилировал его во-первых на VS2013, и он работал так, как я ожидал, с такими результатами:
f(T& a) for lvalues
f(T&& a) for rvalues
Но была одна подозрительная вещь: intellisense подчеркнула f (a). Я сделал некоторые исследования, и я понял, что это потому, что тип рушится (универсальные ссылки, как Скотт Мейерс назвал его), поэтому я подумал о том, что g++ думает об этом. Конечно, он не был составлен. Очень приятно, что Microsoft внедрила свой компилятор для работы более интуитивно понятным способом, но я не уверен, соответствует ли он стандарту и должна ли быть такая разница в IDE (компилятор против intellisense, но на самом деле это может в этом есть смысл). Хорошо, вернемся к проблеме. Я решил это так:
template <typename T>
void f(T& a)
{
std::cout << "f(T& a) for lvalues\n";
}
template <typename T>
void f(const T&& a)
{
std::cout << "f(T&& a) for rvalues\n";
}
Теперь не было никакого коллапсинга типа, просто нормальная перегрузка для (r/l) значений. Он составлен на g++, intellisense перестала жаловаться, и я был почти доволен. Почти, потому что я думал о том, что, если я захочу что-то изменить в состоянии объекта, которое передается ссылкой rvalue? Я мог бы описать некоторую ситуацию, когда это может понадобиться, но это описание слишком длинное, чтобы представить его здесь. Я решил это так:
template <typename T>
void f(T&& a, std::true_type)
{
std::cout << "f(T&& a) for rvalues\n";
}
template <typename T>
void f(T&& a, std::false_type)
{
std::cout << "f(T&& a) for lvalues\n";
}
template <typename T>
void f(T&& a)
{
f(std::forward<T>(a), std::is_rvalue_reference<T&&>());
}
Теперь он компилируется на всех тестируемых компиляторах и позволяет мне изменять состояние объекта в реализации ссылочной ссылки rvalue, но это выглядит не очень хорошо, и это связано с тем же синтаксисом для универсальных ссылок и ссылок на значения rvalue. Поэтому мой вопрос: почему комитет С++ не представил другого синтаксиса для универсальных ссылок? Я думаю, что эта функция должна сигнализироваться, например, T?, auto?, или что-то подобное, но не как T && и авто && которые просто сталкиваются с ссылками rvalue. Используя этот подход, моя первая реализация была бы совершенно правильной не только для MS-компилятора. Может ли кто-нибудь объяснить решение Комитета?