问题描述
我有两种类型 A
和 A_Input
。 A
由 A_Input
构造而成。
我想定义一个模板类 B
,它有两个模板参数,T
和 U
。然后我想为 B
定义一个约束,它要求 T
有一个接受 U
的构造函数。
我尝试编写这样的 B
如下:
template<typename T,typename U>
requires requires (U u) {
T::T(u);
}
class B {
public:
B(){}
void speak() {
std::cout << "success!";
}
};
示例 T
为 class A
,隐含的 U
为 A_Inputs
,如下所示:
class A_Inputs {
public:
A_Inputs(){}
};
class A {
public:
A(A_Inputs ain){}
};
int main() {
B<A,A_Inputs> b{};
b.speak();
return 0;
}
这会给
error C7602: 'B': the associated constraints are not satisfied
解决方法
编写可构造性约束的方法是使用 constructible_from
概念:
template<typename T,typename U>
requires std::constructible_from<T,U>
class B { ... };
,
您应该阅读整个错误消息,而不仅仅是其中的一行。
<source>: In function 'int main()':
<source>:31:18: error: template constraint failure for 'template<class T,class U> requires requires(U u) {(T::T)(u);} class B'
31 | B<A,A_Inputs> b{};
| ^
<source>:31:18: note: constraints not satisfied
<source>: In substitution of 'template<class T,class U> requires requires(U u) {(T::T)(u);} class B [with T = A; U = A_Inputs]':
<source>:31:18: required from here
<source>:7:7: required by the constraints of 'template<class T,class U> requires requires(U u) {(T::T)(u);} class B'
<source>:4:10: in requirements with 'U u' [with T = A; U = A_Inputs]
<source>:5:9: note: the required expression 'T::T(u)' is invalid
5 | T::T(u);
| ~~~~^~~
cc1plus: note: set '-fconcepts-diagnostics-depth=' to at least 2 for more detail
[...]
还有更多关于其他错误的信息,这些错误只是由于 B<A,A_Inputs> b{};
不正确。这里的重要部分是 'T::T(u)'
无效。应该是T(u);
:
#include <iostream>
template<typename T,typename U>
requires requires (U u) {
T(u);
}
class B {
public:
B(){}
void speak() {
std::cout << "success!";
}
};
class A_Inputs {
public:
A_Inputs(){}
};
class A {
public:
A(A_Inputs ain){}
};
class X {
public:
X() {}
};
int main() {
B<A,A_Inputs> b{};
b.speak();
B<X,A_Inputs> x{};
}
这只会按预期为 B<X,A_Inputs> x{};
产生错误,因为约束未满足。
template<class Src,class Dest>
concept can_construct = requires(Src s){
{ Dest(std::forward<Src>(s)); }
}
template<typename T,can_construct<T> U>
class B
喜欢吗?
您应该寻求使用命名概念。这也让您可以为它们添加静态断言测试,以在更简单的上下文中捕获错误。
请注意,can_construct<T> U
需要 can_construct<U,T>
- U 被“加前缀”到概念模板参数中。