升级至GCC12.3后C++20 Concept代码编译失败问题求助
问题背景
示例代码
#include <stop_token> #include <type_traits> template <typename TOwner> concept HasGetStopToken = requires(TOwner& o) { { o.GetStopToken() } -> std::same_as<std::stop_token>; }; template <typename TOwner> class RequestLooper { public: explicit RequestLooper(TOwner& _owner) requires HasGetStopToken<TOwner> : m_owner{ _owner } { } private: TOwner& m_owner; }; class CoreApplication { public: std::stop_token GetStopToken() { return m_stopSource.get_token(); } using Looper = RequestLooper<CoreApplication>; CoreApplication() : m_looper{*this} { } private: Looper m_looper; std::stop_source m_stopSource; };
编译错误信息
In instantiation of 'RequestLooper<TOwner>::RequestLooper(TOwner&) requires HasGetStopToken<TOwner> [with TOwner = CoreApplication]': <source>:31:25: required from here <source>:5:9: required for the satisfaction of 'HasGetStopToken<TOwner>' [with TOwner = CoreApplication] <source>:5:27: in requirements with 'TOwner& o' [with TOwner = CoreApplication] <source>:5:27: error: satisfaction value of atomic constraint 'requires(TOwner& o) {{o->GetStopToken()} -> decltype(auto) [requires std::same_as<<placeholder>, std::stop_token>];} [with TOwner = CoreApplication]' changed from 'false' to 'true' 5 | concept HasGetStopToken = requires(TOwner& o) { | ^~~~~~~~~~~~~~~~~~~~~ 6 | { o.GetStopToken() } -> std::same_as<std::stop_token>; | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | }; | ~ <source>:10:7: note: satisfaction value first evaluated to 'false' from here 10 | class RequestLooper | ^~~~~~~~~~~~~ <source>: In constructor 'CoreApplication::CoreApplication()': <source>:31:25: error: no matching function for call to 'RequestLooper<CoreApplication>::RequestLooper(<brace-enclosed initializer list>)' 31 | CoreApplication() : m_looper{*this} | ^~~~~~~~~~~~~~~ <source>:14:14: note: candidate: 'RequestLooper<TOwner>::RequestLooper(TOwner&) requires HasGetStopToken<TOwner> [with TOwner = CoreApplication]' 14 | explicit RequestLooper(TOwner& _owner) | ^~~~~~~~~~~~~ <source>:14:14: note: constraints not satisfied <source>:10:7: note: candidate: 'constexpr RequestLooper<CoreApplication>::RequestLooper(const RequestLooper<CoreApplication>&)' 10 | class RequestLooper | ^~~~~~~~~~~~~ <source>:10:7: note: no known conversion for argument 1 from 'CoreApplication' to 'const RequestLooper<CoreApplication>&' <source>:10:7: note: candidate: 'constexpr RequestLooper<CoreApplication>::RequestLooper(RequestLooper<CoreApplication>&&)' <source>:10:7: note: no known conversion for argument 1 from 'CoreApplication' to 'RequestLooper<CoreApplication>&&' Compiler returned: 1
核心问题
- 这是已知的编译器bug吗?
- 在Ubuntu22.04上是否有无需更新glibc即可升级至GCC13的方法?
- 是否存在无需移除Concept的代码兼容方案?
解答
1. 是否为已知编译器bug
这确实是GCC 12.3和12.4版本的回归bug。该问题属于C++概念约束在类成员初始化阶段的评估逻辑错误,具体表现为对HasGetStopToken概念的原子约束真值出现前后矛盾的判定。此bug仅存在于GCC 12.3/12.4,在GCC 12.1、12.2以及13.x及以上版本均已修复。
2. Ubuntu22.04无需更新glibc安装GCC13的方法
可以采用以下两种可行方案:
- 使用Snap包安装:Snap包自带独立依赖,不会依赖系统glibc版本。执行命令
sudo snap install gcc --classic --channel=13/stable即可安装GCC13,安装完成后可通过gcc-13或g++-13调用。 - 手动编译GCC13:从GCC官网下载源码包,编译时指定
--with-glibc-version=2.35(Ubuntu22.04默认glibc版本为2.35),并将编译产物安装到非系统目录(如/opt/gcc13),避免覆盖系统原有编译器。编译过程需依赖build-essential、flex、bison等工具,可提前通过apt安装。
3. 无需移除Concept的代码兼容方案
有两种可靠的代码调整方式,均可绕过GCC12.3/12.4的bug:
- 调整类成员声明顺序:将
CoreApplication中std::stop_source m_stopSource的声明移至Looper m_looper之前。修改后代码如下:
class CoreApplication { // ... 其他代码保持不变 private: std::stop_source m_stopSource; // 先声明该成员,确保构造m_looper时已存在 Looper m_looper; };
此方案解决了编译器在评估概念时,因m_stopSource未提前声明导致的约束判定异常。
- 修改Concept的写法:拆分原概念中的返回值类型检查,将其拆分为独立的
requires子句,避免编译器的原子约束判定bug。修改后的Concept如下:
template <typename TOwner> concept HasGetStopToken = requires(TOwner& o) { o.GetStopToken(); // 先确保成员函数可调用 requires std::same_as<decltype(o.GetStopToken()), std::stop_token>; // 单独检查返回值类型 };
内容的提问来源于stack exchange,提问作者mark
相关产品推荐
相关产品推荐

