C++ 返回值类型推导
C++ 返回值类型推导
前言
C++ 中获取函数签名可以很简单地用 decltype(函数名)
来获得,但是这样无法直接提取出返回值类型。
有时我们需要获取函数或可调用对象的返回值类型,以便进行后续的操作,在泛型编程中很常用,特别是当不同的参数集的结果类型不同时。
头文件 <type_traits>
:
-
C++11引入了std::result_of、C++14引入了std::result_of_t
-
C++17中,废弃了std::result_of而引入了更好用的std::invoke_result和std::invoke_result_t。
std::result_of/std::result_of_t
模板类 std::result_of
是一个函数类型萃取器(function type traits),它可以推导函数类型的返回值类型。需要两个模板参数:
- 第一个
F
是可调用类型、对函数的引用或对可调用类型的引用 - 第二个
Args
是函数的参数类型
template< class > class result_of; // 不定义 template< class F, class... ArgTypes > class result_of<F(ArgTypes...)>;
示例1:
#include <type_traits> int add(int x, double y) { return x + static_cast<int>(y); } int main() { std::result_of<decltype(add)>::value result = 0; static_assert(std::is_same<decltype(result), int>::value, "result type should be int"); return 0; }
示例2:
#include <iostream> #include <type_traits> int fn(int) {return int();} // function typedef int(&fn_ref)(int); // function reference typedef int(*fn_ptr)(int); // function pointer struct fn_class { int operator()(int i){return i;} }; // function-like class int main() { typedef std::result_of<decltype(fn)&(int)>::type A; // int typedef std::result_of<fn_ref(int)>::type B; // int typedef std::result_of<fn_ptr(int)>::type C; // int typedef std::result_of<fn_class(int)>::type D; // int std::cout << std::boolalpha; std::cout << "A: " << std::is_same<int,A>::value << std::endl; // true std::cout << "B: " << std::is_same<int,B>::value << std::endl; // true std::cout << "C: " << std::is_same<int,C>::value << std::endl; // true std::cout << "D: " << std::is_same<int,D>::value << std::endl; // true return 0; }
一个模板中应用的实例:
有一个vector
#include <algorithm> #include <iostream> #include <map> #include <string> #include <utility> #include <vector> using namespace std; struct Person { string name; int age; string city; }; vector<Person> vt = { { "aa", 20, "shanghai" }, { "bb", 25, "beijing" }, { "cc", 20, "nanjing" }, { "dd", 25, "nanjing" } }; template <typename Fn> multimap<typename result_of<Fn(Person)>::type, Person> GroupBy(const vector<Person>& vt, const Fn& keySelector) { typedef typename result_of<Fn(Person)>::type key_type; multimap<key_type, Person> ret; // 利用了红黑树map的有序特性来实现分组 for_each(vt.begin(), vt.end(), [&](const Person& p) { ret.insert(make_pair(keySelector(p), p)); }); return ret; } int main() { // 按年龄分组 auto res = GroupBy(vt, [](const Person& p) { return p.age; }); // 按城市分组 auto res1 = GroupBy(vt, [](const Person& p) { return p.city; }); // 打印结果 cout << "----------group by age:---------------" << endl; for_each(res.begin(), res.end(), [](decltype(res)::value_type& p) { cout << p.second.name << " " << p.second.city << " " << p.second.age << endl; }); cout << "----------group by city:---------------" << endl; for_each(res1.begin(), res1.end(), [](decltype(res1)::value_type& p) { cout << p.second.name << " " << p.second.city << " " << p.second.age << endl; }); return 0; }
运行结果:
C++14引入了一个方便的类型别名 std::result_of_t
,它可以替代std::result_of<F(Args...)>::type
,简化代码。
std::invoke_result/std::invoke_result_t
C++17开始,std::result_of
已被弃用,建议使用 std::invoke_result
来代替。std::invoke_result
可以获取函数、成员函数和可调用对象的返回值类型。
与 std::result_of
是,std::invoke_result
支持成员函数指针和指向成员函数的指针,以及可调用对象的包装器 std::function
。
需要两个模板参数:
- 第一个
F
是可调用类型、对函数的引用或对可调用类型的引用、成员函数指针和指向成员函数的指针,以及std::function
- 第二个
Args
是函数的参数类型
template< class F, class... ArgTypes > class invoke_result; // 不定义 template< class F, class... ArgTypes > invoke_result<F, ArgTypes...>;
示例:
#include <type_traits> #include <functional> class A { public: int add(int x, double y) // 成员函数 { return x + static_cast<int>(y); } }; int main() { std::invoke_result<decltype(&A::add), A*, int, double>::type result = 0; static_assert(std::is_same<decltype(result), int>::value, "result type should be int"); std::function<int(int, double)> add = [](int x, double y) { return x + static_cast<int>(y); }; std::invoke_result<decltype(add), int, double>::type result = 0; static_assert(std::is_same<decltype(result), int>::value, "result type should be int"); return 0; }
本文作者:3的4次方
本文链接:https://www.cnblogs.com/3to4/p/18341705
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步