用我们的决心、信心和毅力来培植我们的生|

3的4次方

园龄:2年1个月粉丝:5关注:89

2024-08-04 14:07阅读: 160评论: 0推荐: 0

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,Person就是一个简单的结构体,包含name,age,city三个字段,想要编写一个GroupBy函数,实现对这个vector按Person的某个字段分组。因为字段未定,编写一个模板比较好。思路是向GroupBy传一个函数,让用户决定这个字段。分组比较简单,数据插入一个multimap<T,Person>返回即可。但是定义multimap中的T类型由用户传入的函数决定。于是这时候就可以用result_of来确定函数的返回值,即T的类型.

#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 中国大陆许可协议进行许可。

posted @   3的4次方  阅读(160)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起