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

What is the correct result of std::is_constructible<void()>::value?

std::is_constructible<void()>::value 的结果不一致。我对该标准的解释是它应该是错误的。然而,Clang,同时具有 libc++ 和 libstdc++*,给出了 true。 GCC 和 MSVC 都给出 false。哪个结果是正确的?

标准语

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

Given the following function declaration:

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

the predicate condition for a template specialization is_constructible<T, Args...> shall be satisfied if and only if the following variable definition would be well-formed for some invented variable 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++):

Clang (HEAD, libstdc++)*:

GCC (HEAD, libstdc++):

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


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

继续阅读。来自同一段:

Access checking is performed as if in a context unrelated to T and any of the Args. Only the validity of the immediate context of the variable initialization is considered. [ Note: The evaluation of the initialization can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the “immediate context” and can result in the program being ill-formed. —end note ]

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

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