概念:使用参数检查方法的签名

时间:2016-12-21 15:11:12

标签: c++ c++-concepts

我一直在玩概念。这是我尝试基于方法签名创建概念的最小示例:

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的东西,但我发现情况更糟。

2 个答案:

答案 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");