Cos*_*syn 4 c++ templates overloading c++11
template <typename T> void f(T&) {}
template <typename T> void f(T&&) {}
int main()
{
int x;
f(x); //ambiguous
}
Run Code Online (Sandbox Code Playgroud)
为什么这个电话不明确?第一个模板特化是f <int>(int&),第二个是f <int&>(int&).由于参数相同,因此根据偏序规则更加特殊的函数模板更好.然后根据标准14.8.2.4/9
如果对于给定类型,推导在两个方向上都成功(即,在上面的转换之后类型是相同的)并且P和A都是引用类型(在被上面提到的类型替换之前):
- 如果类型来自参数模板是一个左值引用,而参数模板中的类型不是,参数类型被认为比另一个更专业; ...
第一个模板有T&,第二个模板有T &&,所以第一个应该更专业.这有什么不对?
编辑:此代码在g ++ 4.6.1和VC++ 2010 Express中测试,两者都给出了模糊错误.
指南:
不要过载:
template <typename T> void f(T&) {}
template <typename T> void f(T&&) {}
Run Code Online (Sandbox Code Playgroud)
原因:
模式有一个特殊的模板推导规则:
template <typename T> void f(T&&) {}
Run Code Online (Sandbox Code Playgroud)
存在该规则是为了实现所谓的"完美转发".它可以完美地帮助bind和make_shared完善他们的论点,同时保留cv限定符和"值类别"(左值/右值).
这个特殊规则说,当f(T&&)使用左值参数(例如int)调用时,该T被推导为左值引用(例如int&)而不是int.并且对lvalue引用int的rvalue引用会折叠为对int的lvalue引用.即
f(x)
Run Code Online (Sandbox Code Playgroud)
电话
f<int&>(int& && x);
Run Code Online (Sandbox Code Playgroud)
这简化为:
f<int&>(int& x);
Run Code Online (Sandbox Code Playgroud)
编辑
这不是或多或少专门f<int>(int&).
感谢Johannes Schaub的更正(见评论).
方案:
您可以使用单一功能执行任何操作:
template <typename T> void f(T&&) {}
Run Code Online (Sandbox Code Playgroud)
如果T推导为左值引用,则在第一次重载时执行任何您想要执行的操作,否则在第二次重载时执行任何操作:
template <class T> void f_imp(T&, std::true_type) {std::cout << "lvalue\n";}
template <class T> void f_imp(T&&, std::false_type) {std::cout << "rvalue\n";}
template <typename T> void f(T&& x)
{
f_imp(std::forward<T>(x), std::is_lvalue_reference<T>());
}
Run Code Online (Sandbox Code Playgroud)
并用于std::forward完美转发x到实现细节功能.