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条评论