Я только что наткнулся на это T&&
в классе и функции означает разные вещи.
В функции:
template<class T> void f(T&& t){}; // t is R or L-value
...
int i=0;
f(i); // t in f is lvalue
f(42); // t in f is rvalue
В классе:
template<class T>
struct S {
S(T&& t){} // t is only R-value?
};
...
int i;
S<int> ss(i); // compile error - cannot bind lvalue to ‘int&&’
Означает ли это, что если у нас естьT&& t
в классе, чем t
будет только рвалуе?
Кто-нибудь может указать мне, где я могу получить больше информации об этом?
Означает ли это, что мне нужно написать две перегрузки метода для L и R-значений?
ОТВЕТ
Как показывает пример Альфа, t
в функции и классе может быть Lvalue или Rvalue.
В вашей функции T
выводится из фактического аргумента. Основное использование для этой конкретной комбинации идеальная пересылка. В шаблоне класса T
не выводится, оно должно быть указано.
Например, это прекрасно компилируется как с g ++, так и с msvc:
template<class T>
struct S {
S(T&& t){}
};
int main()
{
int i;
S< int& > ss(i);
}
Вы имеете дело с выводом аргументов шаблона здесь.
Используя f
без явно определяя аргумент шаблона, компиляторы C ++ теперь должны решить, какой тип аргумента шаблона T
от параметров вы передаете его.
Правила вывода аргументов шаблона с &&
типы являются специальными, чтобы обеспечить идеальную пересылку. Когда вы используете f(i)
, T
выводится как T&
, Таким образом, параметр t
имеет тип T& &&
, который падает до T&
, Тем не менее, когда вы используете f(42)
тип T
выводится как T&&
, и поэтому t
является T&& &&
, который падает до T&&
,
Однажды ты сила T
чтобы быть конкретным типом, все, что эффективно уходит. Разрушение все еще может произойти, но потому что вы использовали S<int>
, затем t
будет иметь тип int&&
, S<int> ss(i)
фактически является эквивалентом f<int>(i)
, что тоже не законно. А так как вывод аргументов шаблона работает только с функциями, а не с типами, вы должны сделать что-то подобное для S
если вы хотите совершенную пересылку:
template<class T>
struct S {
template<class U>
S(U&& t){}
};
Конечно, вы можете использовать методы SFINAE и метапрограммирование шаблона, чтобы гарантировать, что шаблон конструктора может быть создан только в том случае, если базовый тип T
а также U
подобные.