如何禁用C++概念评估结果缓存?GCC该行为是否合规?
C++概念评估缓存与GCC行为合规性分析
概念评估的缓存特性
所有编译器都会对C++概念的评估结果进行缓存:若某概念针对同一参数评估为false后,不会再次重新评估。示例代码如下:
template <typename T> concept C = T::a; struct A; static_assert(!C<A>); struct A { static constexpr bool a = true; }; static_assert(C<A>); //< 移除上方static_assert才会通过
禁用缓存的尝试方案
为绕过该缓存机制,可以给概念添加带lambda默认值的额外模板参数(每次实例化会生成唯一的新类型):
template <typename T, auto = []{}> concept C = T::a; struct A; static_assert(!C<A>); struct A { static constexpr bool a = true; }; static_assert(C<A>); //< 仅GCC中失败
该方案在Clang、EDG、MSVC中可正常生效,但GCC仍会复用之前的评估结果导致断言失败。
GCC的行为是否合规?
根据C++标准,概念评估结果的缓存仅针对完全相同的模板实参列表。在修改后的代码中,两次C<A>实例化的第二个模板参数是不同的lambda类型(每个lambda表达式的类型都是唯一的),因此这是两个不同的概念特化,编译器应当重新进行评估,而非复用之前的结果。
GCC的这一行为不符合C++标准的要求,它错误地将这两次不同的实例化视为同一个概念特化,从而复用了缓存的评估结果。
内容的提问来源于stack exchange,提问作者Fedor
相关产品推荐
相关产品推荐

