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()>();
}
结果:
- 静态断言通过
foo<void()>
没有编译
- 静态断言通过
foo<void()>
没有编译
- 静态断言失败
foo<void()>
没有编译
MSVC(通过 http://webcompiler.cloudapp.net/ 的版本 19):
- 静态断言失败
foo<void()>
未编译(需要注释掉静态断言)
*__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 产生错误。
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 variablet
: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()>();
}
结果:
- 静态断言通过
foo<void()>
没有编译
- 静态断言通过
foo<void()>
没有编译
- 静态断言失败
foo<void()>
没有编译
MSVC(通过 http://webcompiler.cloudapp.net/ 的版本 19):
- 静态断言失败
foo<void()>
未编译(需要注释掉静态断言)
*__GLIBCXX__
在没有 -stdlib
选项和 -stdlib=libstdc++
的情况下使用 Clang 时未定义。我不确定 libstdc++ 是否 实际上 正在使用。如果我对标准的解释是正确的,那么我不确定它是 Clang 还是 libc++ 的错误。
继续阅读。来自同一段:
Access checking is performed as if in a context unrelated to
T
and any of theArgs
. 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 产生错误。