【C++】编译期约束类的的接口名称

编译期约束类的的接口名称

首先我们看一下怎样能够在不拿到具体类对象就可以运行其函数。
今天的主角:declval

定义于头文件 <utility>
template<class T>
typename std::add_rvalue_reference<T>::type declval() noexcept;

将任意类型 T 转换成引用类型,令在 decltype 表达式中不必经过构造函数就能使用成员函数。
可以看到其返回类型是一个右值,所以它只能用于不求值语境;求值包含此函数的表达式是错误。

struct Test
{
    int foo(int a)
    {
        cout << "foo" << endl;
        return a * 2;
    }
};

//测试代码
    decltype(declval<Test>().foo(1)) b;
    cout << typeid(b).name() << endl;
//打印
int

可以看到我们在不构造Test的对象即可运行foo的函数。
亦或者我们直接传入该函数所需的类型:

    decltype(std::declval<Test>().foo(std::declval<int>()), std::true_type()) c;
    cout << typeid(c).name() << endl;

同样可以得出以上结论。

约束类接口的细节

直接上代码:

template<typename T, typename ...Args>
typename std::enable_if<std::is_same<decltype(std::declval<T>().foo(std::declval<Args>()...), std::true_type()), std::true_type>::value, void>::type
func(T t, Args&&...args)
{
    t.foo(std::forward<Args>(args)...);
}

该函数func要求,某一类类型必须含有函数foo,并且在该函数使用该类型的foo函数运算。

测试代码如下:

    Test t;
    func(t, 1);

这里有个小技巧就是:

decltype(std::declval<T>().foo(std::declval<Args>()...), std::true_type())

该推导式使用了逗号表达式,对表达式进行推导运算,并且返回一个true类型。假如推导式无法编译通过则不会进行逗号表达式了。

猜你喜欢

转载自blog.csdn.net/gx864102252/article/details/81676158