std :: is_constructible <void()> :: value的正确结果是什么?

时间:2015-10-10 20:57:49

标签: c++ language-lawyer typetraits

我的std::is_constructible<void()>::value结果不一致。我对标准的解释是它应该是假的。但是,使用libc ++和libstdc ++ *的Clang都是真的。 GCC和MSVC都给出了错误。哪个结果是正确的?

Standardese

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

  

给出以下函数声明:

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

模板特化的谓词条件   当且仅当,is_constructible<T, Args...>才会得到满足   对于一些发明的人来说,下面的变量定义会很好   变量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++)

  • 静态断言PASSED
  • foo<void()>没有编译

Clang (HEAD, libstdc++) *:

  • 静态断言PASSED
  • foo<void()>没有编译

GCC (HEAD, libstdc++)

  • 静态断言失败
  • foo<void()>没有编译

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

  • 静态断言失败
  • foo<void()>没有编译(需要注释掉静态断言)
当没有__GLIBCXX__选项和-stdlib使用Clang时,未定义

* -stdlib=libstdc++。我不确定libstdc ++是否实际正在使用。如果我对标准的解释是正确的,那么我不确定它是否是Clang或libc ++的错误。

1 个答案:

答案 0 :(得分:7)

继续阅读。来自同一段:

  

执行访问检查,就好像在与T和。无关的上下文中一样   任何Args只有当前上下文的有效性   考虑变量初始化。 [注意:评估   初始化可能导致副作用,例如实例化   类模板特化和函数模板特化,   生成隐式定义的函数,等等。这样的一面   效果不在“直接上下文”中,并且可能导致   程序不正确。 -end note ]

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

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