简体   繁体   中英

inline constexpr function definition legal or not? gcc (ok) vs clang (error)

My current program is rejected by clang but compiles fine with gcc. It boils down to the following simplified example:

struct A {
  static constexpr inline int one();
};

inline constexpr int A::one() { return 1; }

int main() {
  return 0;
}

g++ 4.7.2 compiles it without errors ( g++ -std=c++11 -Wall -g -o main example.cpp ). clang++ 3.1 rejects it:

$ clang++ -std=c++11 -Wall -g -o main example.cpp 
example.cpp:6:25: error: conflicting types for 'one'
inline constexpr int A::one() { return 1; }
                        ^
example.cpp:3:31: note: previous declaration is here
  static constexpr inline int one();
                              ^
1 error generated.

My bet is that gcc is right and and clang is wrong? The program should be legal C++11.

Interesting sidenote. If one is implemented within the struct, clang no longer complains:

struct A {
  static constexpr inline int one() { return 1; }
}

gcc also accepts this variant. From my understanding, both versions should be identical according to the standard. Is it a clang bug or am I missing something?

This was a Clang bug (fixed in Clang 3.2). The problem was that Clang wasn't correctly handling the impact of implicit const ness when determining whether a redeclaration of a function matched a prior declaration. Consider:

struct A {
  int f();                  // #1
  constexpr int f() const;  // #2 (const is implicit in C++11 and can be omitted)
  static constexpr int g(); // #3
};

int A::f() { return 1; }           // #4, matches #1
constexpr int A::f() { return 1; } // #5, matches #2, implicitly const
constexpr int A::g() { return 1; } // #6, matches #3, not implicitly const

When matching the out-of-class declaration #5 against members of A , the compiler has a problem: it doesn't know what type the new declaration of A::f has yet. If A::f is a non-static member function, then its type is int () const , and if it's a static member function then its type is int () (no implicit const ).

Clang 3.1 didn't get this entirely right: it assumed that if a constexpr function were a member function then the constexpr made it implicitly const , which allows #4 and #5 to work, but breaks #6. Clang 3.2 fixes this by implementing the constexpr -implies- const rule twice: once in redeclaration matching (such that #5 is considered to redeclare #2 and not #1, even though it isn't yet implicitly const ), and again once the prior declaration has been chosen (to add the implicit const to #5).

Although the standard doesn't explicitly mention whether the definition of a constexpr static member function is allowed to be separate from its declaration, it has the following example of a separate definition of a constexpr constructor, under 7.1.5p1:

struct pixel {
  int x;
  int y;
  constexpr pixel(int); // OK: declaration
};
constexpr pixel::pixel(int a)
  : x(square(a)), y(square(a)) // OK: definition
  { }

So it seems clear that constexpr functions can have separate declaration and definition. Also in 7.1.5p1:

If any declaration of a function or function template has constexpr specifier, then all its declarations shall contain the constexpr specifier.

This implies that a constexpr function can have (multiple) non-definition declarations.

I'm pretty sure that g++ is correct. In fact this used to be a bug in g++. I can't find a place in the standard that explicitly says that you can have a static constexpr declaration separate from the definition, but if you look in section 7.1.5 that talks about the constexpr specifier ( summarized here ), it doesn't rule it out, which generally means that it is allowed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM