我目前的程序被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也接受这个变种。根据我的理解,两个版本应该根据标准相同。这是一个铿锵的错误还是我错过了什么?
答案 0 :(得分:10)
这是一个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
- 隐含 - const
规则来解决这个问题:一次在重新声明匹配中(这样#5被认为是重新声明#2而不是#1,即使它还没有隐式const
),并且一旦选择了先前的声明(将隐式const添加到#5),就会再次隐藏。
答案 1 :(得分: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
函数可以有(多个)非定义声明。
答案 2 :(得分:2)
我很确定g ++是正确的。事实上,这曾经是g ++中的bug。我无法在标准中找到一个明确表示你可以将静态constexpr声明与定义分开的地方,但是如果你看一下7.1.5讨论constexpr说明符(summarized here),那么不排除它,这通常意味着它是允许的。