【问题标题】:Is std::declval<void>() a valid expression?std::declval<void>() 是一个有效的表达式吗?
【发布时间】:2017-01-09 21:31:12
【问题描述】:

据我所知,我无法声明对void 的右值引用。
例如,以下代码格式错误:

 void f(void &&v) { }

[20.2.6/1](函数模板declval)我们有一个declval的声明,即:

template <class T>
add_rvalue_reference_t<T>
declval() noexcept;

因此,declval&lt;void&gt;(让我说)将导致void &amp;&amp;,我猜它和前面的例子一样格式不正确。

无论如何,以下最小的工作示例可以编译:

#include<utility>

int main() {
    decltype(std::declval<void>())* ptr = nullptr;
}

请注意,以下也是正确的:

static_assert(std::is_same<decltype(std::declval<void>()), void>::value, "!");

我本来希望它是 void&amp;&amp;,如前所述(或者更好的是,我希望它无法编译)。
实际上,它恰好是任何其他非引用类型的右值引用。
举个例子:

static_assert(std::is_same<decltype(std::declval<int>()), int&&>::value, "!");

declval&lt;void&gt; 是不是一个有效的表达式?上面的代码合法吗?
为什么void 的行为与任何其他类型的行为不同? (否则它不会起作用如果代码是合法的,这可能是一个答案)。

如果它是合法的,那么标准在哪里允许这样做?我没能找到这个案子。
当然,标准说:

declval 的模板参数 T 可能是不完整的类型。

无论如何,这将导致一个不可接受的类型 (void&amp;&amp;) 并且它可以解决它丢弃右值引用。

【问题讨论】:

    标签: c++ c++11 language-lawyer void decltype


    【解决方案1】:

    add_rvalue_reference&lt;T&gt; 仅在 T 是可引用类型时才产生 T&amp;&amp;。所以当Tvoid 时,结果就是void。这也是为什么您可以add_rvalue_reference&lt;int&amp;&amp;&gt; 而在尝试构造对引用的引用时不会出错的原因。 (与左值引用相同。)

    【讨论】:

    • 该死的。现在很明显,您指出了这一点。我没有想到add_rvalue_reference 是如何工作的,我偏向于declval。谢谢你。确实是一个非常愚蠢的问题,但对于那些将来会犯同样错误的人来说,这是一个很好的答案。
    • @skypjack:实际上,我不知道是这种情况,你的问题促使我去看。 :) 好问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多