12

I tried to forward-declare a constexpr variable template like this:

template<typename>
constexpr std::size_t iterator_category_value;

The goal was to document that every specialization should be constexpr but I have to admit that I never checked whether it was legal or not and g++ was happy with it. However, when I tried to compile this spinnet with clang++ instead, I got the following error:

error: default initialization of an object of const type 'const std::size_t' (aka 'const unsigned long')
    constexpr std::size_t iterator_category_value;
                          ^
                                                  = 0

The error makes sense, and removing constexpr makes it disappear, so that's not a real problem. However, I am curious now: does the standard allow such a constexpr forward declaration for a variable template or is it illegal? g++ and clang++ seem to disagree and I would like to know where I should submit a bug report if needed.

Both of them complain for a forward-declared constepxr variable which is not a variable template, so the variable template context seems to be what makes the compilers disagree.

Les
  • 10,335
  • 4
  • 40
  • 60
Morwenn
  • 21,684
  • 12
  • 93
  • 152
  • The text of http://wg21.cmeerw.net/cwg/issue1712 implies that you cannot forward-declare it as `constexpr`, however I'm not quite sure how the std forbids it. A variable template does not looks like an *object declaration* to me. – dyp Oct 18 '15 at 12:40
  • OTOH, [dcl.dcl]p9 seems very general, and should apply to variable templates (=> variable templates are object declarations => `constexpr` requires initialization) – dyp Oct 18 '15 at 12:43
  • @dyp Btw., what do you mean by "now"? Aren't you compiling the most up to date sources currently available on Git? – Columbo Oct 18 '15 at 12:55
  • @Columbo Not regularly :) – dyp Oct 18 '15 at 13:02
  • @dyp Yeah, a variable template declaration being an *object declaration* wasn't really obvious to me, hence the question :/ – Morwenn Oct 18 '15 at 13:18

2 Answers2

10

In the C++14 standard, it seems pretty clear that initialization is required. From section 7.5.1 paragraph 9,

A constexpr specifier used in an object declaration declares the object as const. Such an object shall have literal type and shall be initialized.

As for the exact meaning of "object declaration", Section 7 paragraph 7 states:

If the decl-specifier-seq contains no typedef specifier, the declaration is called a function declaration if the type associated with the name is a function type and an object declaration otherwise.

Morwenn
  • 21,684
  • 12
  • 93
  • 152
Vaughn Cato
  • 63,448
  • 5
  • 82
  • 132
10

Clang is correct. The declaration of a variable template is an object declaration ([dcl.dcl]/9), hence it must provide an initializer as per [dcl.constexpr]/9:

A constexpr specifier used in an object declaration declares the object as const. Such an object […] shall be initialized.

There is effectively no way of "forward" declaring an object as constexpr in the first place, though; If constexpr is applied to the declaration of a variable, it shall be a definition ([dcl.constexpr]/1).

Columbo
  • 60,038
  • 8
  • 155
  • 203