提问者:小点点

内联constexpr函数定义是否合法?gcc(正常)与叮当声(错误)


我当前的程序被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=c11-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是错的?这个程序应该是合法的C11。

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

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

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


共3个答案

匿名用户

这是一个Clang错误(在Clang 3.2中修复)。问题是Clang在确定函数的重新声明是否与之前的声明匹配时,没有正确处理隐式constness的影响。考虑:

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

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

clang3.1并没有完全正确:它假设如果一个CONSTEXR函数是一个成员函数,那么CONSTEXR使它隐式地const,它允许#4和#5工作,但破坏#6。clang 3.2通过两次实现conexpr-implies-const规则来修复这个问题:一次是在重新声明匹配中(这样#5被认为是重新声明#2而不是#1,即使它还没有隐式地const),然后再次一旦选择了先前的声明(将隐式常量添加到#5)。

匿名用户

尽管该标准没有明确提到是否允许将constexpr静态成员函数的定义与其声明分开,但在7.1中,它有一个单独定义constexpr构造函数的示例。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:

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

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

匿名用户

我很确定g是正确的。事实上,这曾经是g中的一个bug。我在标准中找不到明确指出可以将静态constexpr声明与定义分开的地方,但是如果您查看第7.1节。5关于constexpr说明符(这里总结),它不排除它,这通常意味着它是允许的。