【问题标题】:Function initialization with int& argument by int&&通过 int&& 使用 int& 参数初始化函数
【发布时间】:2014-06-20 09:56:27
【问题描述】:

我有以下代码:

#include <type_traits>

struct TType
{
    int a = 0;

    bool operator() (int&)
    {
        return true;
    }
};

int main()
{
    static_assert(std::is_same<decltype(std::declval<TType>()(std::declval<int>())), bool>::value, "wtf?");
    return 0;
}

如果我尝试使用 g++-4.8.2 编译它,则会收到错误消息:

main.cpp:321:82: error: no match for call to ‘(JetPlane) (int)’
static_assert(std::is_same<decltype(std::declval<JetPlane>()(std::declval<int>())), bool>::value, "wtf?");
                                                                                ^
main.cpp:265:8: note: candidate is:
struct JetPlane
       ^
main.cpp:279:7: note: bool JetPlane::operator()(int&)
bool operator() (int&)
     ^
main.cpp:279:7: note:   no known conversion for argument 1 from ‘int’ to ‘int&’

我不明白note: no known conversion for argument 1 from ‘int’ to ‘int&amp;’ 行。所以问题是:尽管 std::declval 声明看起来像:

template< class T >
typename std::add_rvalue_reference<T>::type declval();

我了解禁止将int&amp;&amp; 绑定到int。但是为什么编译器不打印:note: no known conversion for argument 1 from ‘int’ to ‘int&amp;’ 行。可能是我不明白某些东西并且编译器以某种方式从int&amp;&amp; 上的intstd::declval&lt;TType&gt;()(std::declval&lt;int&gt;()) 中的std::declval&lt;int&gt;() 返回类型?

感谢您的帮助!

【问题讨论】:

  • int&amp;&amp; 无法绑定到int&amp;
  • 是的,我明白这一点。但是为什么编译器不打印:没有已知的参数 1 从“int&&”到“int&”的转换
  • 我猜这是出于遗留原因。它是int 类型的右值,并且长期以来意味着类型为int,所以这就是错误报告的内容。是的,在您的情况下,类型是 int&amp;&amp;,但这仍然是 int 右值。

标签: c++ c++11


【解决方案1】:

问题是,您不能将 xvalue 绑定到非 const 左值引用。

我们来看看表达式

std::declval<int>()

std::declval&lt;int&gt; 的返回类型确实是int&amp;&amp;。因此上面的表达式是一个int 类型的xvalue 表达式。请注意,在 C++ 中,表达式从不具有引用类型。

但是你的运营商

bool operator() (int&)

通过非常量左值引用来获取它的参数。如果将参数类型更改为const int&amp;,即

bool operator() (const int&)

一切正常。

【讨论】:

  • 谢谢。那是我怀疑我不知道:“请注意,在 C++ 中,表达式永远没有引用类型。”很好地解释了这个here
【解决方案2】:

您不能使用右值引用来初始化左值引用。令人困惑的是T&amp;&amp; 在不同的上下文中意味着不同的东西:

  • T&amp;&amp;用于定义对象时,右值引用可以绑定到右值,但定义的对象实际上是可以绑定到左值引用的左值
  • T&amp;&amp; 用于声明函数的返回类型时,其含义是返回的右值引用在所有用途中都表现得像临时的,因此不能绑定到左值引用。出于重载解析的所有目的,T&amp;&amp; 类型被视为临时的T,这似乎是编译器报告的内容。

【讨论】:

  • OP 询问为什么 std::declval&lt;int&gt;()int,而不是 int&amp;&amp;
  • 如果 T&amp;&amp; 是返回函数类型,为什么会像 T 一样对待它们?在我看来这是不正确的,因为如果 T&amp;&amp; 返回类型,则函数返回 xvalue,如果 T 正在返回类型,则函数返回 prvalue
  • @ikh:嗯,不是。它恰好被视为在错误消息中,我认为您无法检测到差异,当然对于int 来说不是。对于任意类型,您可能能够根据调用的移动构造函数检测差异(尽管其中一个可能会被省略)。
猜你喜欢
  • 1970-01-01
  • 2012-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多