繁体   English   中英

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

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

我目前的程序被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是正确的,并且铿锵有误? 该程序应该是合法的C ++ 11。

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

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

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

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

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 )。

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

虽然标准没有明确提及的定义是否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函数可以具有(多个)非定义声明。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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