【问题标题】:What is the correct result of std::is_constructible<void()>::value?std::is_constructible<void()>::value 的正确结果是什么?
【发布时间】:2015-10-10 20:57:49
【问题描述】:

std::is_constructible&lt;void()&gt;::value 的结果不一致。我对标准的解释是它应该是错误的。但是,具有 libc++ 和 libstdc++* 的 Clang 给出了 true。 GCC 和 MSVC 都给出错误。哪个结果是正确的?

标准

这里是标准的,N4527 [meta.unary.prop]/7:

给定以下函数声明:

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

模板特化的谓词条件 当且仅当满足is_constructible&lt;T, Args...&gt; 对于某些发明,以下变量定义将是格式良好的 变量t

T t(create<Args>()...);

注意:此文本与 C++11 (N3485) 略有不同,其中 create 未标记为 noexcept。但是,考虑到这一点,我的测试结果并没有改变。

测试用例

这是我对类型特征和标准定义的最小测试用例:

#include <type_traits>

static_assert(std::is_constructible<void()>::value, "assertion fired");

template<typename T>
std::add_rvalue_reference_t<T> create() noexcept;

template<typename T, typename... Args>
void foo() {
    T t(create<Args>()...);   
}

int main() {
    foo<void()>();   
}

结果:

Clang (HEAD, libc++):

  • 静态断言通过
  • foo&lt;void()&gt; 没有编译

Clang (HEAD, libstdc++)*:

  • 静态断言通过
  • foo&lt;void()&gt; 没有编译

GCC (HEAD, libstdc++):

  • 静态断言失败
  • foo&lt;void()&gt; 没有编译

MSVC(版本 19,通过 http://webcompiler.cloudapp.net/):

  • 静态断言失败
  • foo&lt;void()&gt; 没有编译(需要注释掉静态断言)

*__GLIBCXX__ 没有在没有-stdlib 选项和-stdlib=libstdc++ 的情况下使用 Clang 时没有定义。我不确定是否实际上正在使用 libstdc++。如果我对标准的解释是正确的,那么我不确定它是 Clang 还是 libc++ 的错误。

【问题讨论】:

标签: c++ language-lawyer typetraits


【解决方案1】:

继续阅读。来自同一段:

访问检查是在与T 无关的上下文中执行的,并且 任何Args只有直接上下文的有效性 考虑变量初始化。 [ 注意: 初始化可能会导致副作用,例如 类模板特化和函数模板特化, 隐式定义函数的生成,等等。这样的一面 影响不在“直接上下文”中,并且可能导致 程序格式错误。 ——尾注 ]

只有在模板构造函数被实例化时,断言才会失败。但是,正如注释中所澄清的那样,该断言不在所考虑的变量定义的直接上下文中,因此不会影响其“有效性”。因此编译器可以将该定义视为有效,即使实际上尝试构造 void() 会导致程序格式错误。

请注意,编译器也可以根据断言拒绝原始程序,而不是让 is_constructible 产生 false。

【讨论】:

    猜你喜欢
    • 2016-05-02
    • 2013-03-20
    • 1970-01-01
    • 1970-01-01
    • 2016-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-26
    相关资源
    最近更新 更多