template で T&&
rvalue reference については、こことか、こことか、ここら辺に詳しく書いてあります。
さて、rvalue reference ですが、簡単に説明すると次の様な挙動になります。
int n = 0; int&& x1 = 0; int&& x2 = n; // error
これは関数で受け取る場合も同様で、
void func(int&&){} func(0); func(n); // error
このように lvalue で受け取る事は出来ません。
ただし、template 引数で受け取る場合はこれに限らず、
template<typename T> void T_func(T&&){} T_func(0); T_func(n); // ok T が int& となり && は無視される T_func<int>(n); // error int&& で受け取ろうとする
このように、lvalue でも受け取ることができます。
これは、T が T& になり、&& が無視されるからです。
(結果的に lvalue reference で受け取る)
これで T&& と書いておけば rvalue でも lvaleu でも問題なく受け取る事が出来ます。
ただし、明示的に型を指定する場合はその限りではないので注意して下さい。
[注意]
次のコードはエラーになります。
template<typename T> struct holder{ T value; }; template<typename T> holder<T> make_holder(T&& t){ return { t }; } // error: conversion from 'holder<int&>' to non-scalar type 'holder<int>' requested int n = 0; holder<int> v = make_holder(n);
これは、T が T& になり、holder
これを解決するためには、std::remove_reference を使用します。
#include <type_traits> template<typename T> struct holder{ T value; }; template<typename T> holder<typename std::remove_reference<T>::type> make_holder(T&& t){ return { std::forward<T>(t) }; } int n = 0; holder<int> v = make_holder(n); // ok