equal-l2
equal-l2

Reputation: 969

Why can't constexpr member used for static_assert?

This code rejected by clang because t.n is not compile-time constant.

template<int N>
struct s{
  constexpr static int n = N;
};

template<typename T>
void test(T& t){
  static_assert(t.n == 1);
}

int main(){
  s<1> str;
  test(str);
}

But g++ let this go.

Which is the standard-compliant behavior?

One more curious fact is, if I change test's argument from T& t to T t, this will build on both. What is changed about const-ness?

(I afraid the title may not describe this question correctly, or in detail. Feel free to give me more suitable title)

Upvotes: 2

Views: 336

Answers (2)

Curious
Curious

Reputation: 21540

I don't know the reason for the compiler error but if you change the code to use the scope resolution operator to access the static variable then the code will compile on both compilers

#include <iostream>

using namespace std;

template<int N>
struct s{
    constexpr static int n = N;
};

template<typename T>
void test(T&){
    static_assert(T::n == 1, "blah");
}

int main(){
  s<1> str;
  test(str);
}

Upvotes: 0

Brian Bi
Brian Bi

Reputation: 119477

I believe (but with low confidence) that Clang is correct, because according to the standard, a core constant expression may not contain:

an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either

— it is initialized with a constant expression or

— it is a non-static data member of an object whose lifetime began within the evaluation of e;

and t is a variable of reference type. Assuming (as I do, with low confidence) that "preceding initialization" means initialization that is lexically in scope at the point where the would-be constant expression occurs, since the initialization of a parameter occurs in the scope of the caller, t does not satisfy this requirement, so t.n indeed cannot be used in a constant expression.

If the parameter type is changed to T then this disqualifying bullet point no longer applies.

(Even if you accept my interpretation, there is still ambiguity; see CWG 2186)

Upvotes: 2

Related Questions