<PR 18283> C++ 03 - Need clarification regarding non-type template argument

Hi all,

Note - this is with respect to C++ 03.

Test code:

template struct A {};
int const i = {42};
typedef A Ai;

For non-type template argument, standard (C++ 03) says that:

14.3.2 / 1

A template-argument for a non-type, non-template template-parameter shall be one of:

  • an integral constant-expression of integral or enumeration type; or …
    For the test code above, the statement ‘typedef A Ai’, should the compiler
    check the rhs (rvalue) of variable ‘i’ to determine if it is a constant or not?
    Shouldnt it just check the type of i (which is declared as const)?
    Whether ‘i’ evaluates to constant (at compile time) or not should be the responsibility of compiler
    while processing statement ‘int const i = {42}’ and not 'typedef A Ai’ ? Isnt it?

Another analogy:
For arrays, the size of the array needs to be a compile time constant. So, the following code :

int const x = 42;
int z[x];

For the statement ‘int z[x]’, will the compiler evaluate the rhs of ‘x’ to check if it evaluates to constant at runtime
or will it just see that ‘x’ is of ‘integer const’ type and hence there is no problem with the array declaration?
Whether ‘x’ evaluates to constant should be the responsibility of compiler while processing statement ‘int const x=42
and not while processing ‘int z[x]’ ?

Should this analogy be applicable to non-type template argument?

Please throw some light on this, am I missing any particular case?

Thanks,

Rahul

201301101351858_QKNMBDIF.gif

Hi all,

Note - this is with respect to C++ 03.

Test code:

template struct A {};
int const i = {42};
typedef A Ai;

Short, snarky answer - you can’t bracket-initialize a variable in c++03
int const i = {42};

For non-type template argument, standard (C++ 03) says that:

14.3.2 / 1

A template-argument for a non-type, non-template template-parameter shall be one of:

  • an integral constant-expression of integral or enumeration type; or …
    For the test code above, the statement ‘typedef A Ai’, should the compiler
    check the rhs (rvalue) of variable ‘i’ to determine if it is a constant or not?
    Shouldnt it just check the type of i (which is declared as const)?
    Whether ‘i’ evaluates to constant (at compile time) or not should be the responsibility of compiler
    while processing statement ‘int const i = {42}’ and not 'typedef A Ai’ ? Isnt it?

Another analogy:
For arrays, the size of the array needs to be a compile time constant. So, the following code :

int const x = 42;
int z[x];

For the statement ‘int z[x]’, will the compiler evaluate the rhs of ‘x’ to check if it evaluates to constant at runtime
or will it just see that ‘x’ is of ‘integer const’ type and hence there is no problem with the array declaration?
Whether ‘x’ evaluates to constant should be the responsibility of compiler while processing statement ‘int const x=42
and not while processing ‘int z[x]’ ?

Should this analogy be applicable to non-type template argument?

Please throw some light on this, am I missing any particular case?

My understanding (which may be flawed) is that the compiler needs to see both:

  • That the compiler needs to be able to determine that the value it needs is const
  • That the compiler can see what the value actually is, so that it can allocate space for the array, or instantiate the template.

So, this would not work:

extern const int i;
template struct A {};
typedef A Ai;

Hi all,

Note - this is with respect to C++ 03.

*Test code:*

*template <int> struct A {};int const i = {42};typedef A<i> Ai;*

Short, snarky answer - you can’t bracket-initialize a variable in c++03

You can in a few cases: specifically, if the type is an aggregate or a
scalar type. In the latter case,

   T x = { a };

is equivalent to

  T x = a;

(See C++03 [dcl.init](8.5)/13.)

int const i = {42};

For non-type template argument, standard (C++ 03) says that:
*14.3.2 / 1*

*A template-argument for a non-type, non-template template-parameter shall
be one of:*

   - *an integral constant-expression of integral or enumeration type; or
   ......*

For the test code above, the statement '*typedef A<i> Ai*', should the
compiler
check the rhs (rvalue) of variable 'i' to determine if it is a constant or
not?

Yes. For 'i' to be an integral constant-expression, it can only mention
"const variables [...] of integral or enumeration types initialized with
constant expressions" (C++03 [expr.const](5.19)/1). So the compiler is
required to check whether 'i' is indeed initialized by a constant
expression.

Shouldnt it just check the type of i (which is declared as const)?

Whether 'i' evaluates to constant (at compile time) or not should be the
responsibility of compiler
while processing statement '*int const i = {42}*' and not '*typedef A<i>
Ai' ? Isnt it?*

Another analogy:
For arrays, the size of the array needs to be a compile time constant. So,
the following code :

*int const x = 42;*
*int z[x];*

For the statement *'int z[x]'*, will the compiler evaluate the rhs of
*'x'* to check if it evaluates to constant at runtime
or will it just see that '*x*' is of 'integer const' type and hence there
is no problem with the array declaration?
Whether '*x*' evaluates to constant should be the responsibility of
compiler while processing statement '*int const x=42*'
and not while processing '*int z[x]*' ?

Should this analogy be applicable to non-type template argument?

According to the C++ standard, the two cases are exactly the same. However,
to support code relying on GCC extensions, we allow any constant-foldable
expression as an array bound, whereas we require a constant-expression as a
template argument. Use -pedantic-errors to enable Clang's
strictly-conforming mode, where we (incorrectly) reject both cases.

The bug is that CheckICE in lib/AST/ExprConstant.cpp (or
maybe VarDecl::checkInitIsICE) doesn't handle the case of an InitListExpr
being used to initialize a scalar.

Please throw some light on this, am I missing any particular case?

My understanding (which may be flawed) is that the compiler needs to see
both:
* That the compiler needs to be able to determine that the value it needs
is const
* That the compiler can see what the value actually is, so that it can
allocate space for the array, or instantiate the template.

So, this would not work:

extern const int i;
template <int> struct A {};
typedef A<i> Ai;

Right.