它是Visual C ++ 2010中的错误还是正确的行为?
template<class T>
T f(T const &r)
{
return r;
}
template<class T>
T f(T &&r)
{
static_assert(false, "no way"); //< line # 10
return r;
}
int main()
{
int y = 4;
f(y); //< line # 17
}
我想,函数f(T&amp;&amp;)不应该被调用,但是用T = int&amp;调用它。输出:
main.cpp(10): error C2338: no way main.cpp(17) : see reference to function template instantiation 'T f(T)' being compiled with [ T=int & ]
更新1 您知道任何C ++ x0编译器作为参考吗?我已经尝试了在线测试驱动但无法编译r值参考。
更新2 解决方法(使用SFINAE):
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_reference.hpp>
template<class T>
T f(T &r)
{
return r;
}
template<class T>
typename ::boost::disable_if< ::boost::is_reference<T>, T>::type f(T &&r)
{
static_assert(false, "no way");
return r;
}
int main()
{
int y = 4;
f(y);
// f(5); // generates "no way" error, as expected.
}
更新3 即使没有函数模板实例化,一些编译器也会触发static_assert(false,“no way”)。解决方法(感谢@Johannes Schaub - litb)
template<class T> struct false_ { static bool const value = false; };
...
static_assert(false_<T>::value, "no way");
或
static_assert(sizeof(T) == sizeof(T), "no way");
答案 0 :(得分:5)
据我了解(我可能不完全正确;规范有点复杂),模板类型扣除规则对你不利。
编译器首先尝试替换所有模板(此时尚未选择 - 仅查找选项)并获取:
T const &r
将int
左值与T = int
匹配,创建 f(int const &)
T &&r
匹配int
左值与T = int&
和int & &&
缩减为int&
,创建 {{1} } (spec中有规则说明这一点。)现在谈到选择正确的重载,后者是更好的匹配,因为第一个在cv-qualification中有所不同而后者没有。这也是为什么当你删除f(int &)
时,你得到模糊的重载错误 - 重载最终完全相同。
广告 Update1 :gcc支持many of the C++0x features。您可以从mingw获取原生Windows构建版本,也可以使用cygwin。
广告 Update2 :如果你真的需要rvalue和lvalue的单独重载,那似乎是唯一的选择。但是大多数模板只使用任何类型的引用做正确的事情,可能使用const
来确保它们调用的函数的正确解析,这取决于它们是否具有rvalue或lvalue。
答案 1 :(得分:3)
您的修复程序无法解决static_assert
解雇的问题。 static_assert(false, ...)
仍将触发在定义时解析模板的编译器(大多数都是)。
他们会看到任何函数模板实例化都会格式不正确,而标准允许他们为模板本身发出错误,而大多数人都会这样做。
为了完成这项工作,您需要使表达式依赖,以便编译器不知道它何时解析模板,它总是评估为false。例如
template<class> struct false_ { static bool const value = false; };
template<class T>
T f(T &&r)
{
static_assert(false_<T>::value, "no way"); //< line # 10
return r;
}