【问题标题】:Visual C++ 2010, rvalue reference bug?Visual C++ 2010,右值引用错误?
【发布时间】:2011-02-18 06:27:08
【问题描述】:

这是 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 &&) 永远不应该被调用,但它是用 T = int & 调用的。输出:

main.cpp(10):错误 C2338:没办法 main.cpp(17) : 请参阅正在编译的函数模板实例化 'T f(T)' 的参考 和 [ T=整数& ]

更新 1 你知道任何 C++x0 编译器作为参考吗?我已经尝试过 comeau 在线试驾,但无法编译 r-value 参考。

更新 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");

【问题讨论】:

  • 我想知道 static_assert(false, ...) 并不总是被触发是不是 Visual C++ 的特殊性?对于 G++,断言必须依赖于模板参数才能触发,除非函数被实例化。
  • 我认为这是 Visual C++ 的“功能”。对其他编译器使用 'static_assert(sizeof(T) == sizeof(F), "no way")'。
  • 不合规当然不是特征。无论如何,sizeof(T) == 0 是使断言始终失败但要依赖的好方法。 (我有一个always_false&lt;T&gt;::value 模板。)
  • @GMan 同意。我在引号中写了“功能”。一种幽默。
  • 我添加了一个答案来指出这一点。由于问题是为什么会触发 static_assert,我认为最好有一个静态的答案。

标签: c++ visual-c++ c++11 visual-c++-2010 rvalue-reference


【解决方案1】:

据我了解(我可能并不完全正确;规范有点复杂),模板类型推导规则对你不利。

编译器首先尝试替换所有模板(此时它还没有选择——只是寻找选项)并得到:

  • T const &amp;rint 左值与T = int 匹配,创建f(int const &amp;)
  • T &amp;&amp;r 匹配int 左值与T = int&amp;int &amp; &amp;&amp; 减少到int&amp;,创建f(int &amp;)(在@987654321 中有这样的规则@)。

现在选择正确的重载,后者更好地匹配,因为第一个在 cv-qualification 上不同,而后者则没有。这也是为什么当您删除 const 时,您会得到模棱两可的重载错误 - 重载最终完全相同。

广告更新1gcc 支持many of the C++0x features。您可以从mingw 或使用cygwin 获取本机Windows 构建。

Ad Update2:如果你真的需要单独的右值和左值重载,那似乎是唯一的选择。但是大多数模板只使用任何类型的引用就可以做正确的事情,也许使用std::forward 来确保它们调用的函数的正确解析,具体取决于它们是获得右值还是左值)。

【讨论】:

【解决方案2】:

您的修复并没有解决static_assert 触发的问题。 static_assert(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;
}

【讨论】:

  • 我同意 static_assert 需要对某些编译器进行此修复。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多