如何检查类型是否具有 constexpr 构造函数
How to check a type has constexpr constructor
我希望我的 class 对没有 constexpr 构造函数的类型使用另一个实现。
像这样:
template <typename A>
class foo
{
public:
// if A has constexpr constructor
constexpr foo() :_flag(true) { _data._a = A(); }
// else
constexpr foo() : _flag(false) { _data.x = 0; }
~foo(){}
bool _flag;
union _data_t
{
_data_t() {} // nothing, because it's just an example
~_data_t() {}
A _a;
int x;
}_data;
};
为了实现标题所说的,我尝试这样做:
template<typename _t, _t = _t()>
constexpr bool f()
{
return true;
}
template<typename _t>
constexpr bool f()
{
return false;
}
它适用于没有 constexpr 构造函数的类型。
但对于其他类型,它会导致编译错误和不明确的重载。
那我怎么检查呢?
我想您可以将 SFINAE 与逗号运算符的强大功能结合使用
按照你的想法,你可以重写你的f()
函数如下
template <typename T, int = (T{}, 0)>
constexpr bool f (int)
{ return true; }
template <typename>
constexpr bool f (long)
{ return false; }
注意技巧:int = (T{}, 0)
第二个模板参数
仅当 T{}
可以构造为 constexpr(因为 (T{}, 0)
是模板参数的参数)时,才启用 f()
(逗号运算符的强大功能),否则 SFINAE擦除 f()
.
的第一个版本
并观察 f()
的第一个版本收到未使用的 int
,而第二个版本收到 long
。这样,第一个版本是首选,如果可用,用 int
调用 f()
;选择第二个,总比没有好,当第一个不可用时(当第一个模板参数不是 constexpr 默认构造时)。
现在您可以为 foo
构造两个模板构造函数,您可以根据模板参数 T
(默认为 A
)是或不是的事实来选择 enable/disable 't constexpr 构造
template <typename T = A,
std::enable_if_t<f<T>(0), std::nullptr_t> = nullptr>
constexpr foo() { std::cout << "constexpr" << std::endl; }
template <typename T = A,
std::enable_if_t<not f<T>(0), std::nullptr_t> = nullptr>
constexpr foo() { std::cout << "not constexpr" << std::endl; }
以下是一个完整的编译示例(C++14 或更新版本,但您可以针对 C++11 进行修改):
#include <iostream>
#include <type_traits>
template <typename T, int = (T{}, 0)>
constexpr bool f (int)
{ return true; }
template <typename>
constexpr bool f (long)
{ return false; }
template <typename A>
struct foo
{
template <typename T = A,
std::enable_if_t<f<T>(0), std::nullptr_t> = nullptr>
constexpr foo() { std::cout << "constexpr" << std::endl; }
template <typename T = A,
std::enable_if_t<not f<T>(0), std::nullptr_t> = nullptr>
constexpr foo() { std::cout << "not constexpr" << std::endl; }
};
struct X1 { constexpr X1 () {} };
struct X2 { X2 () {} };
int main()
{
foo<X1> f1; // print "constexpr"
foo<X2> f2; // print "not constexpr"
}
我希望我的 class 对没有 constexpr 构造函数的类型使用另一个实现。
像这样:
template <typename A>
class foo
{
public:
// if A has constexpr constructor
constexpr foo() :_flag(true) { _data._a = A(); }
// else
constexpr foo() : _flag(false) { _data.x = 0; }
~foo(){}
bool _flag;
union _data_t
{
_data_t() {} // nothing, because it's just an example
~_data_t() {}
A _a;
int x;
}_data;
};
为了实现标题所说的,我尝试这样做:
template<typename _t, _t = _t()>
constexpr bool f()
{
return true;
}
template<typename _t>
constexpr bool f()
{
return false;
}
它适用于没有 constexpr 构造函数的类型。 但对于其他类型,它会导致编译错误和不明确的重载。
那我怎么检查呢?
我想您可以将 SFINAE 与逗号运算符的强大功能结合使用
按照你的想法,你可以重写你的f()
函数如下
template <typename T, int = (T{}, 0)>
constexpr bool f (int)
{ return true; }
template <typename>
constexpr bool f (long)
{ return false; }
注意技巧:int = (T{}, 0)
第二个模板参数
仅当 T{}
可以构造为 constexpr(因为 (T{}, 0)
是模板参数的参数)时,才启用 f()
(逗号运算符的强大功能),否则 SFINAE擦除 f()
.
并观察 f()
的第一个版本收到未使用的 int
,而第二个版本收到 long
。这样,第一个版本是首选,如果可用,用 int
调用 f()
;选择第二个,总比没有好,当第一个不可用时(当第一个模板参数不是 constexpr 默认构造时)。
现在您可以为 foo
构造两个模板构造函数,您可以根据模板参数 T
(默认为 A
)是或不是的事实来选择 enable/disable 't constexpr 构造
template <typename T = A,
std::enable_if_t<f<T>(0), std::nullptr_t> = nullptr>
constexpr foo() { std::cout << "constexpr" << std::endl; }
template <typename T = A,
std::enable_if_t<not f<T>(0), std::nullptr_t> = nullptr>
constexpr foo() { std::cout << "not constexpr" << std::endl; }
以下是一个完整的编译示例(C++14 或更新版本,但您可以针对 C++11 进行修改):
#include <iostream>
#include <type_traits>
template <typename T, int = (T{}, 0)>
constexpr bool f (int)
{ return true; }
template <typename>
constexpr bool f (long)
{ return false; }
template <typename A>
struct foo
{
template <typename T = A,
std::enable_if_t<f<T>(0), std::nullptr_t> = nullptr>
constexpr foo() { std::cout << "constexpr" << std::endl; }
template <typename T = A,
std::enable_if_t<not f<T>(0), std::nullptr_t> = nullptr>
constexpr foo() { std::cout << "not constexpr" << std::endl; }
};
struct X1 { constexpr X1 () {} };
struct X2 { X2 () {} };
int main()
{
foo<X1> f1; // print "constexpr"
foo<X2> f2; // print "not constexpr"
}