使用 class 模板和 std::void_t 检查默认构造函数
Checking for a default Constructor using class templates with std::void_t
下面是试图在编译时检查是否存在默认构造函数的代码片段。使用
编译
clang version 11.0.0
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /usr/local/opt/llvm/bin
使用选项 clang++ --std=c++17 -o test_default_ctor test_default_ctor.cpp
#include <type_traits>
template<typename T, typename = void>
struct has_default_ctor_1 : std::false_type {};
template<typename T>
struct has_default_ctor_1<T, std::void_t<decltype(T())>> : std::true_type {};
template<typename T, typename = void>
struct has_default_ctor_2 : std::false_type {};
template<typename T>
struct has_default_ctor_2<T, std::void_t<decltype(T{})>> : std::true_type {};
struct Test1 {
Test1() = default;
};
struct Test2 {
Test2() {}
};
struct Test3 {
Test3() = delete;
};
int main() {
static_assert(has_default_ctor_1<Test1>::value, "Test has default ctor");
static_assert(has_default_ctor_2<Test1>::value, "Test has default ctor");
static_assert(has_default_ctor_1<Test2>::value, "Test has default ctor");
static_assert(has_default_ctor_2<Test2>::value, "Test has default ctor");
static_assert(not has_default_ctor_1<Test3>::value, "Test has default ctor");
static_assert(not has_default_ctor_2<Test3>::value, "Test has default ctor");
}
编译的输出将是
test_default_ctor.cpp:33:5: error: static_assert failed due to requirement '!has_default_ctor_2<Test3, void>::value' "Test has default ctor"
static_assert(not has_default_ctor_2<Test3>::value, "Test has default ctor");
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
问题是为什么在模板特化中使用 ()
与 {}
进行构造函数调用使其在一种情况下有效而在另一种情况下无效?
template<typename T>
struct has_default_ctor_2<T, std::void_t<decltype(T{})>> : std::true_type {};
当您检查 T{}
是否格式正确时,您还允许可以通过聚合初始化的方式初始化的类型。 Test3
是 C++20 之前的集合 class,因为它没有 用户提供的 构造函数。来自[dcl.fct.def.default]/5 [摘录,强调我的]:
[...] A function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration.
有关不同标准版本聚合的详细信息,请参见例如:
Aggregates in C++20
As of C++20, particularly due to the implementation of P1008R1 (Prohibit aggregates with user-declared constructors) most of the frequently surprising aggregate behaviour covered above has been addressed, specifically by no longer allowing aggregates to have user-declared constructors, a stricter requirement for a class to be an aggregate than just prohibiting user-provided constructors.
下面是试图在编译时检查是否存在默认构造函数的代码片段。使用
编译clang version 11.0.0
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /usr/local/opt/llvm/bin
使用选项 clang++ --std=c++17 -o test_default_ctor test_default_ctor.cpp
#include <type_traits>
template<typename T, typename = void>
struct has_default_ctor_1 : std::false_type {};
template<typename T>
struct has_default_ctor_1<T, std::void_t<decltype(T())>> : std::true_type {};
template<typename T, typename = void>
struct has_default_ctor_2 : std::false_type {};
template<typename T>
struct has_default_ctor_2<T, std::void_t<decltype(T{})>> : std::true_type {};
struct Test1 {
Test1() = default;
};
struct Test2 {
Test2() {}
};
struct Test3 {
Test3() = delete;
};
int main() {
static_assert(has_default_ctor_1<Test1>::value, "Test has default ctor");
static_assert(has_default_ctor_2<Test1>::value, "Test has default ctor");
static_assert(has_default_ctor_1<Test2>::value, "Test has default ctor");
static_assert(has_default_ctor_2<Test2>::value, "Test has default ctor");
static_assert(not has_default_ctor_1<Test3>::value, "Test has default ctor");
static_assert(not has_default_ctor_2<Test3>::value, "Test has default ctor");
}
编译的输出将是
test_default_ctor.cpp:33:5: error: static_assert failed due to requirement '!has_default_ctor_2<Test3, void>::value' "Test has default ctor"
static_assert(not has_default_ctor_2<Test3>::value, "Test has default ctor");
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
问题是为什么在模板特化中使用 ()
与 {}
进行构造函数调用使其在一种情况下有效而在另一种情况下无效?
template<typename T> struct has_default_ctor_2<T, std::void_t<decltype(T{})>> : std::true_type {};
当您检查 T{}
是否格式正确时,您还允许可以通过聚合初始化的方式初始化的类型。 Test3
是 C++20 之前的集合 class,因为它没有 用户提供的 构造函数。来自[dcl.fct.def.default]/5 [摘录,强调我的]:
[...] A function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration.
有关不同标准版本聚合的详细信息,请参见例如:
Aggregates in C++20
As of C++20, particularly due to the implementation of P1008R1 (Prohibit aggregates with user-declared constructors) most of the frequently surprising aggregate behaviour covered above has been addressed, specifically by no longer allowing aggregates to have user-declared constructors, a stricter requirement for a class to be an aggregate than just prohibiting user-provided constructors.