Reputation: 43969
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?
Upvotes: 16
Views: 3366
Reputation: 14158
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).
Upvotes: 10
Reputation: 157334
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 theconstexpr
specifier.
This implies that a constexpr
function can have (multiple) non-definition declarations.
Upvotes: 8
Reputation: 9124
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.
Upvotes: 2