C++ 可调用对象返回值类型推导

类型萃取获得返回值类型

这里用到了模板元编程技术,标准库中有现成的实现 std::result_of,原理是这样的:
我们通过 decltype(f(args)) 来获得返回类型,那么就得有函数 f 的类型和参数 args 的类型

类型萃取设计如下:

// 不会使用该版本
template<typename Func, typename... Args>
struct return_type{};

// 使用特化版本
template<typename Func, typename... Args>
struct return_type<Func(Args...)>{
    using type = decltype(declval<Func>()(declval<Args>()...));
};

我们通过 return_type<func(args)>::type 的方式来获得其返回类型,在具体实现中,decltype(declval<Func>()(declval<Args>()...)) 其实就是 decltype(f(args)) 的具体版本,declval<Func>() 的含义是返回一个类型 Func 的右值,但实际上不绑定任何数据,是一个空对象,只能表示类型。(declval<Args>()...) 是函数的参数列表,所以这一整句直观上的具体含义就是调用 Func 并传入参数,通过 decltype 自动推导出其返回值类型。

其中 declval 的实现也非常简单,如下:

template<typename L_Value, typename R_Value = L_Value&&>
R_Value declval(){};

所以通过类型萃取获得返回类型可以如下实现:

int test(int, double){
	return 1;
}

return_type<decltype(test)&(int, double)>::type interger;

注意如果是传入普通函数必须是函数指针或函数引用的形式,函数对象不用,具体参考 C++11 的 std::result_of,本文中的 declvalreturn_type 都是简化形式,且不支持成员函数,完整实现参考 std::result_of

通过 decltype 获得返回值类型

上述的设计非常麻烦,一般人通常使用不到类型萃取的技巧,一般这种技巧在设计库时才会用到,在一般的应用场景中,更方便获得返回类型的是 decltype(f(args)),直接到位。

template<typename Func, typename... Args>
void func(Func&& f, Args&&... args){
    using type = decltype(f(args...));
    type integer = 0;
}

// 使用
int test(int, double){
    return 1;
}

int main(){
    func(test, 1, 1.1);
    return 0;
}

通过参数推导类型,可以非常方便地获得返回类型,但是缺点就是需要封装一层函数,不够灵活。类型萃取是通过类型推导出返回类型,灵活性更高。

模板参数 && 是万能引用,并不代表是右值

上一篇 下一篇

评论 | 0条评论