C++20中Concept与Constraint的正确定义位置及编译问题解析
C++20中Concept与Constraint的正确定义位置解析
问题重现
可正常编译的代码
void f(int x) { } template <typename T> concept Concept = requires (T a) { f(a); }; template <typename T> requires Concept<T> struct A { }; int main(){ A<int> a; }
编译失败的代码(调整f(int)位置后)
template <typename T> concept Concept = requires (T a) { f(a); }; void f(int x) { } // <-- 调整后的位置 template <typename T> requires Concept<T> struct A { }; int main(){ A<int> a; }
GCC 11.3.0报错信息:
main.cpp:27:10: error: template constraint failure for ‘template<class T> requires Concept<T> struct A’ 27 | A<int> a; | ^ main.cpp:27:10: note: constraints not satisfied main.cpp: In substitution of ‘template<class T> requires Concept<T> struct A [with T = int]’: main.cpp:27:10: required from here main.cpp:12:9: required for the satisfaction of ‘Concept<T>’ [with T = int] main.cpp:13:5: in requirements with ‘T a’ [with T = int] main.cpp:14:8: note: the required expression ‘f(a)’ is invalid 14 | { f(a); };
编译失败原因解析
Concept的约束检查遵循定义点查找规则:当判断Concept是否满足时,编译器会使用Concept定义时作用域内可见的名字,而非模板实例化时的作用域。
在编译失败的代码中,定义Concept时,f(int)还未被声明,此时作用域内没有匹配f(a)(当T=int时)的函数。尽管后续声明了f(int),但Concept的约束逻辑已经在定义时绑定了当时的名字查找结果,实例化A<int>时无法回溯到后续声明的函数,因此约束检查失败。
Concept与Constraint的正确定义位置规则
- Concept中引用的非ADL可见名字,必须在Concept定义前声明/定义:如果Concept的requires表达式里用到的函数、类型等无法通过依赖于参数的查找(ADL)自动找到,就必须保证这些名字在Concept定义时已经存在于当前作用域或可见命名空间中。
- Constraint的位置要求:只要在模板(类/函数)定义时,对应的Concept已经被定义即可,无需提前于所有被Concept引用的名字,但Concept本身的定义必须满足上述第一条规则。
- 依赖ADL的情况:如果Concept中调用的函数是与模板参数
T关联的(比如T是自定义类型,函数f属于该类型所在的命名空间),则可以在Concept定义后声明,但必须保证实例化时ADL能找到该函数。
内容的提问来源于stack exchange,提问作者Antonio
相关产品推荐
相关产品推荐

