C++20/23中consteval成员函数调用合法性:哪款编译器合规?
C++20/23中consteval成员函数调用的编译器行为正确性分析
测试代码
#include <cstddef> template <size_t N> class Foo { public: consteval size_t size() noexcept { return N; } size_t real_size() { return size() - 1; } }; int main(int argc, char* argv[]) { Foo<5> foo; return foo.real_size(); }
不同编译器的编译结果
- Clang 10与GCC 14.1:无错误、无警告编译通过
- Clang 14至18.1版本:触发编译错误,错误信息如下:
<source>:9:20: error: call to consteval function 'Foo<5>::size' is not a constant expression 9 | return size() - 1; | ^ <source>:15:16: note: in instantiation of member function 'Foo<5>::real_size' requested here 15 | return foo.real_size(); | ^ <source>:9:20: note: implicit use of 'this' pointer is only allowed within the evaluation of a call to a 'constexpr' member function 9 | return size() - 1; | ^
问题与解答
问题
依据C20与C23标准,哪款编译器的行为是正确的?原因是什么?
解答
正确的行为是Clang 14-18.1报错,GCC 14.1和Clang 10的编译通过属于不符合标准的宽松实现,原因如下:
- consteval函数的调用要求:C++标准规定,
consteval函数必须在常量表达式语境中调用,且调用结果必须是常量表达式。 - this指针的语境限制:
size()是非静态consteval成员函数,调用时会隐式传递this指针。而real_size()是普通成员函数,不属于常量表达式语境——即使Foo<5>是模板实例化类型,this指向的对象是运行时创建的,此时调用consteval函数时,this的值无法在编译期确定,不符合常量表达式的要求。 - 标准条款依据:标准明确指出,隐式使用
this指针的consteval成员函数调用,仅当整个调用处于常量表达式语境时才被允许。非常量表达式语境下的此类调用属于非法行为。
Clang 14及后续版本修正了早期实现的错误,严格遵循标准;而GCC 14.1和Clang 10未正确执行该检查,属于非标准的宽松处理。
内容的提问来源于stack exchange,提问作者HCSF
相关产品推荐
相关产品推荐

