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
,本文中的 declval
和 return_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条评论