调用不完整类型成员函数:GCC编译通过Clang/VS不通过,谁合规?
C++代码跨编译器兼容性问题
示例代码
struct TestClass { void testFunction() const {} static TestClass* ptr_; constexpr static auto funcPtr = +[](){ ptr_->testFunction(); }; }; TestClass* TestClass::ptr_ = new TestClass(); int main() { TestClass::funcPtr(); delete TestClass::ptr_; return 0; }
这段代码可通过GCC编译,但无法通过Clang和MSVC编译。问题:哪款编译器的行为符合C++标准?这是否是GCC的bug?
Clang错误信息
<source>:4:46: error: member access into incomplete type 'TestClass' 4 | constexpr static auto funcPtr = +[](){ ptr_->testFunction(); }; | ^ <source>:1:8: note: definition of 'TestClass' is not complete until the closing '}' 1 | struct TestClass { | ^ 1 error generated. Compiler returned: 1
MSVC错误信息
example.cpp <source>(4): error C2027: use of undefined type 'TestClass' <source>(1): note: see declaration of 'TestClass' <source>(4): error C2131: expression did not evaluate to a constant <source>(4): note: failure was caused by call of undefined function or one not declared 'constexpr' <source>(4): note: see usage of 'TestClass::<lambda_bdad2d00eade3d9eccb85c581305196c>::operator void (__cdecl *)(void)' Compiler returned: 2
解答
Clang和MSVC的行为符合C++标准,GCC允许这段代码编译属于非标准行为,是一个bug。
原因有两点:
- 类类型不完全的问题:在
TestClass的定义内部(直到闭合}之前),该类属于不完全类型。lambda表达式中通过ptr_->testFunction()访问类的非静态成员函数,此时编译器还未获取类的完整定义,根据C++标准,这种访问是不被允许的——编译器无法确认成员函数的存在和内存布局。 - 常量表达式的要求:
constexpr static成员的初始化表达式必须是常量表达式,即能在编译期完成计算。但这里的lambda内部调用了ptr_->testFunction(),而ptr_是在类外部通过new动态初始化的,属于运行时操作,完全不符合常量表达式的要求,MSVC指出的“表达式未求值为常量”正是对这一标准要求的体现。
内容的提问来源于stack exchange,提问作者Георгий Гуминов
相关产品推荐
相关产品推荐

