The following code uses enum member m
as a constant expression, i.e. as a template parameter. The code compiles under gcc but not under clang (live demo). Clang says "error: non-type template argument is not a constant expression".
The problem can be solved by exchanging line // 1
by A<tst<p>::m> a
. Therefore, my question is not how to fix this issue but which compiler is right.
template<size_t n> struct A{};
template<size_t n>
struct tst
{ enum : size_t { m= n % 15 };
template<size_t p>
void
call( tst<p> const &t2 ) {
A<t2.m> a; // 1
}
};
Enums are lists of constants. When you need a predefined list of values which do represent some kind of numeric or textual data, you should use an enum. You should always use enums when a variable (especially a method parameter) can only take one out of a small set of possible values.
Enum values or Enum instances are public, static, and final in Java. They are a compile-time constant, which means you can not changes values of Enum instances and further assignment will result in a compile-time error.
An enumeration is a user-defined type that consists of a set of named integral constants that are known as enumerators. This article covers the ISO Standard C++ Language enum type and the scoped (or strongly-typed) enum class type which is introduced in C++11.
A const Enum is the same as a normal Enum. Except that no Object is generated at compile time. Instead, the literal values are substituted where the const Enum is used.
According to the Standard, Clang is right to reject the code.
t2.m
is a class member access expression. [expr.ref]/1 says:
[...] The postfix expression before the dot or arrow is evaluated; the result of that evaluation, together with the id-expression, determines the result of the entire postfix expression.
There's also a note:
If the class member access expression is evaluated, the subexpression evaluation happens even if the result is unnecessary to determine the value of the entire postfix expression, for example if the id-expression denotes a static member.
So, the subexpression t2
is evaluated. [expr.const]/2.9 says that an expression e
cannot be a core constant expression if evaluating it results in the evaluation of
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
- its lifetime began within the evaluation of
e
;
t2
refers to a variable of reference type that doesn't satisfy the bullets, so t2.m
is not a constant expression because it isn't a core constant expression.
All quotes from N4594, the current published working draft. The text has changed slightly since C++11, but the meaning in this case is the same.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With