C++98 curly brace const scalar initialization

1k views Asked by At

I stumbled upon the code which I do not understand. Here's a simplified version of it:

template <int> struct A {};

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

int const j = 42;
typedef A<j> Aj;

This code compiles with GCC in C++98 mode, but not in Clang. Clang produces the following error:

$ clang -Wall -Wextra -std=c++98 -c test.cpp

test.cpp:4:11: error: non-type template argument of type 'int' is not an integral constant expression
typedef A<i> Ai;
          ^
test.cpp:4:11: note: initializer of 'i' is not a constant expression
test.cpp:3:11: note: declared here
int const i = { 42 };
          ^

As far as I understand initialization of int with and without curly braces should be equivalent. Clang initializes i correctly to 42, just doesn't think it's a compile time constant.

This code compiles well in C++11 mode.

Is there a reason j is treated as a compile time constant and i is not? Or is it simply a bug in Clang?

Update: I opened a ticket in LLVM bug tracker with this issue.

3

There are 3 answers

0
Raxvan On BEST ANSWER

The compiler error states that "template argument of type 'int' is not an integral constant expression" for int const i = { 42 };

According to 98 standard the template argument should fall into this category:

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

...

and the definition of integral constant expression int const i fall into this category:

5.19 Constant expressions

An integral constant-expression can involve only literals (2.13), enumerators, const variables or static data members

and for the initialization of i (like Mike Seymour post):

8.5 Initializers /13

If T is a scalar type, then a declaration of the form

T x = { a };

is equivalent to

T x = a;

Now based on this post the declaration of const int and int const should be the same (could not find this specifically in standard) making i a const variable. So any usage of i should be an integral constant expression regardless of the initialization method. It appears there is a bug in clang. Checking the web i could not find a bug report only two more or less similar:

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=666539

and

http://lists.cs.uiuc.edu/pipermail/llvmbugs/2011-March/017353.html

0
Vlad from Moscow On

I think that Clang is right. initializer list is not an expression. There is a difference between initialization of aggregate objects and fundamental objects. When a POD object is initialized then each initializer can be considered as a const expression. However when you deal with fundamental types then initializer list is not an expression and is not a const expression.

In paragraph #14 of the Standard there is written:

The source type is not defined when the initializer is brace-enclosed or when it is a parenthesized list of expressions

0
Mike Seymour On

Yes, both declarations are equivalent, per C++98 8.5/13:

If T is a scalar type, then a declaration of the form

T x = { a };

is equivalent to

T x = a;

So both variables are constant, and initialised from a constant expression, so (as far as I can see) should both be usable as constant expressions.