fja*_*sze 6 c++ templates rvalue-reference template-specialization
我对这个小例子有点困惑:
using mytype = std::vector<std::string>;
template<typename T>
void test(T item)
{
throw std::runtime_error(typeid(item).name());
}
template<>
void test(std::vector<std::string>&& vec)
{
std::cout<<"Ok."<<std::endl;
}
int main()
{
mytype stuff;
test(std::forward<mytype>(stuff));
}
Run Code Online (Sandbox Code Playgroud)
我希望在这里为调用选择专门的模板,但事实并非如此,删除&&
将使这种情况发生(并且参数移至vec
)..
为什么test
没有使用专门用于右值参数的版本?
为什么没有使用专门用于右值参数的测试版本?
std::forward<mytype>(stuff)
这是因为您传递的函数参数是一个表达式,而C++ 中的表达式绝不是某种引用类型。也就是说,函数调用参数的类型std::forward<mytype>(stuff)
实际上是std::vector<std::string>
而不是std::vector<std::string>&&
。换句话说,T
将被推导出为std::vector<std::string>
和 not std::vector<std::string>&&
。
基本上,您已经为模板参数专门化了函数模板std::vector<std::string>&&
,但T
被推导为std::vector<std::string>
. 因此,无法使用专业化。另一方面,如果您要删除,&&
那么将调用专业化(请参阅答案末尾的解释)。
让我们看一个人为的例子来澄清这个问题:
我添加以下示例来表明我的上述解释是正确的。
template <class T> void f(T)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void g() {
f((const int&)0); //T will be deduced as int and not "const int" or even "const int&"
f((int&&)0); //T will be deduced as int and not "int&&"
}
int main()
{
g();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
工作演示。
template<typename T>
void test(T item) //#1
{
std::cout<<"generic"<<std::endl;
}
template<>
void test(int&& vec) //#2
{
std::cout<<"Ok."<<std::endl;
}
int main()
{
int stuff = 0;
//---vvvvvvvvvvvvvvvvvvvvvvvv----------->the argument is an expression and is of type int instead of int&&
test(std::forward<int>(stuff)); //calls #1
}
Run Code Online (Sandbox Code Playgroud)
在上面的示例中,表达式std::forward<int>(stuff)
的类型为int
and not int&&
,因此T
被推导为int
(and not int&&
)。这意味着将调用通用版本。
删除 && 将会实现这一点
当您删除 时&&
,那么这一次您将明确专门化函数模板 forstd::vector<std::string>
和 not std::vector<std::string>&&
。这意味着这一次,推导的T
结果与您为其专门化函数模板的模板参数匹配,因此调用了专门化。