3

Is this code Standard-Compliant?

class Example {
    public:
        static int x;
};

decltype(auto) Example::x = 1;

int main(){ return 0; }

Clang 3.9.1 compiles it successfully, but gcc 6.3.0 fails: error: conflicting declaration 'decltype(auto) Example::x'

C++14 Standard (ISO/IEC 14882:2014), Section 7.1.6.4, Paragraph 5 (emphasis mine):

A placeholder type can also be used in declaring a variable in the condition of a selection statement (6.4) or an iteration statement (6.5), in the type-specifier-seq in the new-type-id or type-id of a new-expression (5.3.4), in a for-range-declaration, and in declaring a static data member with a brace-or-equal-initializer that appears WITHIN the member-specification of a class definition (9.4.2).

The (re)declaration is not strictly within the member-specification of a class definition, but I don't see any good reason to forbid it. Furthermore, it can be seen also as a (re)declaration of a variable (static data member variable) in namespace scope, which is allowed in Paragraph 4:

The type of a variable declared using auto or decltype(auto) is deduced from its initializer. This use is allowed when declaring variables in a block (6.3), in namespace scope (3.3.6), and in a for-init-statement (6.5.3).

There is a similar C++11 post: Why doesn't the C++11 'auto' keyword work for static members? However, there is only one answer, and then a debate starts in the comments. Besides, clang is usually more reliable in this cases, and according to that answer clang would be wrong and gcc would be correct.

Community
  • 1
  • 1
José Luis
  • 397
  • 1
  • 11
  • 2
    I think it’s just not really clear what the standard intends (i think it intends to disallow this) and what it actually requires (i think it actually allows this). Also see http://stackoverflow.com/questions/26386010 – Darklighter Mar 24 '17 at 14:56
  • @Darklighter Interesting discussion in the link you provide, and by the way I agree with your opinion, so I will just assume I cannot rely on the behavior of this feature. Thanks for your comment. – José Luis Mar 28 '17 at 15:22

1 Answers1

1

It seems gcc becomes confused since it tries to infer the type of x from the rvalue in its initialization and NOT its declaration in the Example class. This can result in an inconsistency between the two types, making it look like you are defining a new variable with the same name.

If I understood correctly, the behavior that you are looking for can be implemented with standard-compliant code by using a macro which explicitly infers the type from the variable declaration:

#define auto_typed_init(a) decltype(a) a

(...)

auto_typed_init(Example::x) = 2;

I don't understand, however, why the standard favors the initializer in this case, as is explained in this answer: Why doesn't the C++11 'auto' keyword work for static members?

Sinitax
  • 11
  • 4