Home > Net >  Why can't constexpr be used for non-const variables when the function only uses the types?
Why can't constexpr be used for non-const variables when the function only uses the types?

Time:09-01

Maybe the title is not clear, so concretely:

#include <type_traits>

template<typename T>
constexpr int test(T)
{
    return std::is_integral<T>::value;
}

int main()
{
    constexpr int a = test(1); // right
    constexpr int b = test(1.0); // right
    int c = 2;
    constexpr int d = test(c); // ERROR!
    return 0;
}

In fact, the function doesn't use anything but the type of the parameter, which can be determined obviously in the compilation time. So why is that forbidden and is there any way to make constexpr get the value when only the type of parameter is used?

In fact, I hope to let users call the function through parameters directly rather than code like test<decltype(b)>, which is a feasible but not-convenient-to-use way, to check if the types of parameters obey some rules.

CodePudding user response:

Just take T by reference so it doesn't need to read the value:

template<typename T>
constexpr int test(T&&)
{
    return std::is_integral<std::remove_cvref_t<T>>::value;
}

You can even declare test with consteval, if you want to.

(Note that stripping cv-qualifiers isn't necessary in this instance; cv-qualified integral types satisfy the std::is_integral trait.)

CodePudding user response:

Why can't constexpr be used for non-const variables when the function only uses the types?

Because the call expression test(c) is not a constant expression and hence it cannot be used as an initializer for d.

Basically, for the call expression test(c) to be a constant expression, c must be a constant expression. It doesn't matter whether c is used or not inside the function itself. This is why, the call expressions test(1) and test(1.0) works and can be used as an initializer for a and b respectively.

  • Related