内联constexpr函数定义是否合法?gcc(ok)vs clang(错误)

Phi*_*ßen 15 c++ clang language-lawyer c++11

我目前的程序被clang拒绝,但是用gcc编译好.它归结为以下简化示例:

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

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

int main() {
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

g ++ 4.7.2编译它没有错误(g++ -std=c++11 -Wall -g -o main example.cpp).clang ++ 3.1拒绝它:

$ 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.
Run Code Online (Sandbox Code Playgroud)

我敢打赌,gcc是正确的,并且铿锵有误?该程序应该是合法的C++ 11.

有趣的旁注.如果one在结构中实现,则clang不再抱怨:

struct A {
  static constexpr inline int one() { return 1; }
}
Run Code Online (Sandbox Code Playgroud)

gcc也接受这个变种.根据我的理解,两个版本应该根据标准相同.这是一个铿锵的错误还是我错过了什么?

Ric*_*ith 10

这是一个Clang bug(在Clang 3.2中修复).问题是,const在确定函数的重新声明是否与先前的声明匹配时,Clang没有正确处理隐含的影响.考虑:

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
Run Code Online (Sandbox Code Playgroud)

当将类外声明#5与成员匹配时A,编译器有一个问题:它不知道新声明的类型A::f.如果A::f是非静态成员函数,则其类型为int () const,如果它是静态成员函数,则其类型为int ()(无隐式const).

Clang 3.1并没有完全正确:它假设如果一个constexpr函数是一个成员函数,那么constexpr它就是隐含的const,它允许#4和#5工作,但是#6打破了.Clang 3.2通过两次实现constexpr-implies- const规则来解决这个问题:一次在重新声明匹配中(这样#5被认为是重新声明#2而不是#1,即使它还没有隐含const),并且一旦先前的声明已经有了被选中(将隐式const添加到#5).


eca*_*mur 8

尽管该标准没有明确提及constexpr静态成员函数的定义是否允许与其声明分开,但它具有以下constexpr7.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
  { }
Run Code Online (Sandbox Code Playgroud)

所以很明显,constexpr函数可以有单独的声明和定义.同样在7.1.5p1中:

如果函数或函数模板的任何声明都有constexpr说明符,那么它的所有声明都应该包含说明constexpr 符.

这意味着constexpr函数可以具有(多个)非定义声明.