c++ - стандарт - cppreference if constexpr




static_assert, если выражения constexpr (2)

Я хочу создать шаблон класса

template <class T>
class X {
  // here I'll use T::value (among other things)
};

T::value часто является статической переменной constexpr, но не всегда. T::value должно быть положительным, поэтому я хочу, чтобы люди знали это во время компиляции, когда это возможно.

Если T::value всегда было constexpr, я бы добавил static_assert как

static_assert(T::value > 0, "need positive number");

Можно ли добавить этот static_assert только в случаях, когда T::value constexpr?


Мы можем написать is_valid шаблона is_valid (придумать лучшее имя) с двумя перегрузками:

template <typename T, int N = T::value>
constexpr bool is_valid(int) {
    return N > 0;
}

template <typename T>
constexpr bool is_valid(...) {
    return true;
}

Первая перегрузка будет действительна только в том случае, если T::value является постоянным выражением, иначе это будет SFINAEd. Вторая перегрузка действительна, несмотря ни на что, поэтому мы устраняем перегрузку с параметром фиктивного int .

Теперь мы тестируем его так:

static_assert(is_valid<T>(0), "need positive number");

Демо-версия


Это работает для меня на clang ++:

#include <type_traits>

// The default case, returns true if the value is not constant.
template <typename T, typename = void>
struct IsNonConstantOrPositive {
    static const bool value = true;
};

// The `constexpr` case. We check if we can evaluate `T::value == 0` which can only
// be evaluated at compile-time if `T::value` is constant. The whole `enable_if` thing
// is to provide a substitution to ensure SFINAE.
template <typename T>
struct IsNonConstantOrPositive<T, typename std::enable_if<T::value==0||true>::type> {
    static const bool value = T::value > 0;
};

template <typename T>
struct X {
    static_assert(IsNonConstantOrPositive<T>::value, "T::value should be positive");
};

Пример:

struct A {  // const > 0, should succeed
    static const int value = 123;
};

struct B {  // const <= 0, should fail
    static const int value = -1234;
};

struct C {   // non-const, should succeed
    static int value;
};

int main() {
    X<A> a;     // ok
    //X<B> b;   // error
    X<C> c;     // ok
}




static-assert