c ++中的依赖类型,非零类型

时间:2017-04-04 13:58:36

标签: c++ types

让我们说这是一个非零能力的裸骨。

template<typename T>
struct NonZero {
    T val;
};

我的问题是,是否可以为NonZero创建一个构造函数,以获取T类型的字面值并静态检查它是否为非零然后分配它到val

NonZero<int> n( 0 ); // compilation error
NonZero<int> n( 1 ); // ok

或者是否有更好的方法来实现非零类型?

3 个答案:

答案 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