16

我当前的程序被clang拒绝,但用gcc编译得很好。它归结为以下简化示例:

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

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

int main() {
  return 0;
}

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.

我敢打赌 gcc 是对的,而 clang 是错的?该程序应该是合法的 C++11。

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

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

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

4

3 回答 3

10

这是一个 Clang 错误(在 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

在将类外声明 # A5A::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),然后再次在先前的声明中被选中(将隐式常量添加到#5)。

于 2013-07-05T18:02:51.797 回答
8

尽管该标准没有明确提及是否constexpr允许将静态成员函数的定义与其声明分开,但它constexpr在 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
  { }

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

如果函数或函数模板的任何声明具有constexpr说明符,则其所有声明都应包含说明constexpr 符。

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

于 2012-12-17T11:11:40.960 回答
2

我很确定 g++ 是正确的。事实上,这曾经是 g++ 中的一个错误。我在标准中找不到明确说明您可以将静态 constexpr 声明与定义分开的地方,但是如果您查看第 7.1.5 节讨论 constexpr 说明符(在此处总结),它不会排除它,这通常意味着它是允许的。

于 2012-12-17T04:54:03.863 回答