我当前的程序被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错误还是我错过了什么?
最佳答案
这是一个 Clang 错误(在 Clang 3.2 中修复)。问题在于,在确定函数的重新声明是否与先前的声明匹配时,Clang 没有正确处理隐式 const
ness 的影响。考虑:
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)。
关于c++ - 内联 constexpr 函数定义是否合法? gcc (ok) vs clang (error),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13907252/