我一直在玩概念。这是我尝试基于方法签名创建概念的最小示例:
template<typename T>
concept bool myConcept() {
return requires(T a, int i) {
{ a.foo() } -> int;
{ a.bar(i) } -> int;
};
}
struct Object {
int foo() {return 0;}
int bar(int) {return 0;}
};
static_assert(myConcept<Object>(), "Object does not adhere to myConcept");
令我惊讶的是,{ a.bar(int) } -> int
写不起作用,所以我试图在requires
表达式中添加一个额外的参数。这看起来有点奇怪,我想知道是否有办法做同样的事情。另一件有用的事情是使用类似{ a.bar((int)0) } -> int
的东西,但我发现情况更糟。
答案 0 :(得分:6)
概念检查表达式,而{% render %}
不是一个。通过写作
a.bar(int)
您要求编译器检查前面提到的表达式是否为{ a.foo(int) } -> int
类型。这没有意义。
你确实找到了一个有效的选择;另一个可能是,因为int
的类型不依赖于a.bar(x)
'值:
x
答案 1 :(得分:3)
由于该类型的实际值并不重要,我建议使用int{}
作为参数。这证明了论证的目的有点好,IMO:
{ a.bar(int{}) } -> int;
显然,这不适用于没有默认构造函数的类型。在模板中,可以使用std::declval
来解决类似问题,但这里是GCC错误:
error: static assertion failed: declval() must not be used!
但没有什么可以阻止我们编写等效(但未实现)的函数来与概念一起使用,如下所示:
#include <type_traits>
template <class T>
typename std::add_rvalue_reference<T>::type makeval();
template<typename T>
concept bool myConcept() {
return requires(T a, int i) {
{ a.foo() } -> int;
{ a.bar(makeval<int>()) } -> int;
};
}
struct Object {
int foo() {return 0;}
int bar(int) {return 0;}
};
static_assert(myConcept<Object>(), "Object does not adhere to myConcept");