为何传递const右值时C++模板函数匹配结果与《C++ Primer》不符?
关于C++模板函数匹配const右值的疑惑
测试代码
#include <iostream> #include <string> #include <utility> using namespace std; template<typename T> void func(T&& t){ cout << "T&&" << endl; } template<typename T> void func(const T& t){ cout << "const T&" << endl; } int main() { const string s1 = "b"; func(std::move(s1)); return 0; }
运行结果
T&&
《C++ Primer》中文版相关描述
// Template function binding to non-const rvalue template <typename T> void f(T&&); // Template function binding to lvalue and const rvalue template <typename T> void f(const T&)正如非模板函数一样,第一个版本绑定到可修改的右值,而第二个版本绑定到左值或const右值。
问题分析
这里的核心是模板参数推导、引用折叠规则以及函数重载的匹配优先级:
- 传递
std::move(s1)时,表达式类型是const string&&(s1是const string,std::move将其转为const右值引用)。 - 第一个模板
func(T&&)中,模板参数T会被推导为const string,经引用折叠后参数类型就是const string&&,和实参类型完全匹配。 - 第二个模板
func(const T&)中,模板参数T会被推导为string,参数类型是const string&,虽然const string&&可以隐式绑定到const string&,但这种属于转换匹配,优先级远低于第一个模板的完全匹配。
所以编译器会优先选择第一个模板,和你看到的运行结果一致。
《C++ Primer》的描述存在语境限制:它大概率是在对比非模板函数的重载逻辑——非模板的void f(T&&)确实只能绑定非const右值,void f(const T&)可以绑定左值和const右值,但模板中的T&&是万能引用,推导规则和非模板右值引用完全不同,能匹配包括const右值在内的所有值类别,这时就得看匹配的精确程度来选择重载版本。
内容的提问来源于stack exchange,提问作者scFei
相关产品推荐
相关产品推荐

