让我们说这是一个非零能力的裸骨。
template<typename T>
struct NonZero {
T val;
};
我的问题是,是否可以为NonZero
创建一个构造函数,以获取T
类型的字面值并静态检查它是否为非零然后分配它到val
。
NonZero<int> n( 0 ); // compilation error
NonZero<int> n( 1 ); // ok
或者是否有更好的方法来实现非零类型?
答案 0 :(得分:5)
由于该值在编译时已知,因此您可以将其设为模板参数并使用std::enable_if
:
template<typename T, T x>
struct NonZero {
const static std::enable_if_t<x != T(0), T> value = x;
};
用法:
int x = NonZero<int, 1>::value; // OK
int x2 = NonZero<int, 0>::value;// Compilation error
答案 1 :(得分:3)
另一种选择是在constexpr
构造函数中检查值为零:
template<typename T>
struct NonZero {
const T value;
constexpr NonZero(const T val) :
value(val != 0 ? val : throw std::runtime_error("should be non-zero"))
{}
};
用法:
NonZero<int> v(1); // OK
NonZero<int> v2(0); // Compiles OK, but throws in run-time
constexpr NonZero<int> v3(1); // OK
constexpr NonZero<int> v4(0); // Compilation error
此方法仅适用于constexpr
变量,但看起来更直接。
此外,您可以使用struct
函数或用户定义的文字,而不是使用带有constexpr
构造函数的constexpr
,而是使用完全相同的想法。
答案 2 :(得分:1)
想到另一种方法,它将为您提供一个以值作为参数的构造函数。
核心思想是使构造函数模板化并将值作为模板参数传递。不幸的是,以直截了当的方式做到这一点是不可能的,但我们可以使用this question的解决方法:
template<typename T>
struct NonZero {
const T value;
template<T x>
NonZero(std::integral_constant<std::enable_if_t<x != T(0), T>, x>) : value(x) {
}
};
用法:
auto v = NonZero<int>(std::integral_constant<int, 1>()); // OK
auto v2 = NonZero<int>(std::integral_constant<int, 0>()); // Compilation error