现代C++讲解之变量模板,泛型lambda,函数返回类型推导的使用

本篇目标:

学会C++14中新增加的变量模板,泛型lambda,函数返回类型推导

一.变量模板

1.概念

通过之前对C++11的学习,我们已经知道:类模板允许定义一个类的家族,函数模板允许你定义一个函数的家族一样,那么变量模板允许你定义一个变量的家族。

2.使用

在 C++14 之前,如果我们想要定义一个圆周率,并且希望它能根据不同的类型(如 int, float, double)有不同的精度,写法会比较笨重,例如:

cpp 复制代码
#include<iostream>

using namespace std;

template<class T>
class MathConstants 
{
public:
	static constexpr T pi = T(3.1415926535897932385L);
};
int main()
{
	double pi = MathConstants<double>::pi;
	return 0;
}

我们不仅要定义一个类来封装pi,而且使用时很啰嗦。

C++14 引入变量模板后的做法**,** 有了变量模板,可以直接对变量进行模板化,摆脱了毫无意义的类包装,例如:

cpp 复制代码
template<class T>
constexpr T pi = T(3.1415926535897932385L);

使用时,我们就可以直接这样用:

cpp 复制代码
cout.precision(6);
cout << "float π: " << pi<float> << endl;
cout.precision(10);
cout << "double π: " << pi<double> << endl;

注:cout.precision(6); 是 中用来控制浮点数(小数)输出精度的语句。

二.泛型lambda

1.C++11与C++14对比使用

假如我们想写一个简单的 Lambda 来实现两个变量相加,如果用 Lambda来完成**,** 那么就需要把类型写死,例如想加 int,得写一个;如果想加 double,又得再写一个,如代码所示:

cpp 复制代码
int main()
{
	auto SumInt = [](int a, int b) { return a + b; };
	auto SumDouble = [](double a, double b) { return a + b; };
	return 0;
}

但是在C++14允许lambda表达式使用auto作为参数类型,使其成为泛型,如代码所示:

cpp 复制代码
auto add = [](auto a, auto b) { return a + b; };

cout << add(1, 2) << endl;           // 传入 int,推导出 int,输出 3
cout << add(3.14, 2.5) << endl;      // 传入 double,推导出 double,输出 5.64

那么lambda可以使用auto后,那么也可以使用auto&代表左值引用的形参,auto&&代表万能引用的的形参,auto&&...代表可变模板参数的万能引用。,如代码所示:

cpp 复制代码
auto getMax = [](const auto& a, const auto& b) {return a > b ? a : b;};
int main()
{
	cout << "最大整数: " << getMax(10, 20) << std::endl;
	cout << "最大字符串: " << getMax(string("apple"), string("banana")) << endl;
	return 0;
}
cpp 复制代码
auto func = [](auto&& x, auto& y)
    {
        x += 97;
        y += 97;
    };

int main()
{
    int i = 10, j = 1;
    func(j, i);
    cout << "i=" << i << endl;
    cout << "j=" << j << endl;
    return 0;
}
cpp 复制代码
int main()
{
    vector<string> v;
    auto f1 = [&v](auto&&... ts)
        {
            v.emplace_back(forward<decltype(ts)>(ts)...);
        };
    string s1 = "love you";
    f1(s1);
    f1(move(s1));
    f1("1111111");
    f1(10, 'y');
    for (auto& e : v)
    {
        cout << e << " ";
    }
    cout << endl;
    return 0;
}

2.补充

1.C++14允许在lambda捕获中使用表达式初始化捕获的变量,这个变量可以是当前域定义的,也可以是没有定义的 ,例如:

cpp 复制代码
int main() {
    vector<int> numbers = { 1, 2, 3, 4, 5 };

    auto p = make_unique<int>(10);
    auto lambda1 = [value = 5, ptr = std::move(p), &numbers]() 
        {
        cout << "捕获的值: " << value << endl;
        cout << "捕获的智能指针值: " << *ptr << endl;
        cout << "捕获的vector大小: " << numbers.size() << endl;
        };
    lambda1();
    return 0;
}

注意:捕获的值得是其所在作用域非静态局部变量,否则会报错。

2.C++20以后开始支持在捕捉列表和参数列表中间直接类似模板语法写模板参数,具体参考下面的代码。

cpp 复制代码
int main()
{
    auto add = []<class T>(T a, T b) { return a + b; };
    cout << add(10, 20) << endl;
    cout << add(52.3, 20.60) << endl;
    return 0;
}

当然也可以这样写:

cpp 复制代码
int main()
{
    auto glambda = []<class T>(T a, auto && b) { return a < b; };
    cout << add(10, 20) << endl;
    cout << add(52.3, 20.60) << endl;
    return 0;
}
cpp 复制代码
int main()
{
    vector<string> v;
    auto f1 = [&v]<class... Args>(Args&&... ts)
        {
            v.emplace_back(forward<Args>(ts)...);
        };
    string s1 = "love you";
    f1(s1);
    f1(move(s1));
    f1("1111111");
    f1(10, 'y');
    for (auto& e : v)
    {
        cout << e << " ";
    }
    cout << endl;
    return 0;
}

三.函数返回类型推导

1.C++11与C++14对比使用

C++11中普通函数用auto做函数返回类型推导时,⼀般要求要配合尾置返回类型使用,相对比较局 限,例如:

cpp 复制代码
auto add(auto a, auto b) -> decltype(a + b) 
{
    return a + b;
}

int main()
{
    cout << add(1, 2) << endl;
    string s1("like");
    string s2("you");
    cout << add(s1,s2) << endl;
    return 0;
}
cpp 复制代码
int x = 1;
auto f1() -> int { return x; }        
auto f2() -> int& { return x; }       
auto f3(int x) -> decltype(x * 1.5) { return x * 1.5; } // 
 
int main()
{
    cout << f1() << endl;
    int& ret = f2();
    cout << f3(3) << endl;
    ret++;
    cout << x << endl;
    cout << ret << endl;
    return 0;
}

C++14后普通函数可以直接用auto 做返回类型,自动推导返回类型,如果有多条返回语句,那么它们必须推导出相同的类型,例如:

cpp 复制代码
int x = 1;
auto f1() { return x; }
auto& f2() { return x; }
auto f3(int x) { return x * 1.5; }

auto f4(int x) 
{
    if (x > 0)
        return 1.0;
    else
        return 2;   // 报错,多返回语句需类型一致
}

但是我们也知道:auto无法推导&,顶层const,如果我们想要准确的返回类型,此时就可以使用decltype(auto),例如:

cpp 复制代码
int x = 1;
decltype(auto) f1() { return x; }    
decltype(auto) f2() { return (x); }

template<typename F, typename... Args>
decltype(auto) call(F && f, Args&&... args)
{
    return forward<F>(f)(forward<Args>(args)...);
}
int main()
{
    cout << f1() << endl;
    int& ret = f2();
    ret++;
    cout << x << endl;
    cout << ret << endl;
    return 0;
}
相关推荐
郝学胜-神的一滴3 小时前
[简化版 GAMES 101] 计算机图形学 07:图形学投影完全推导
c++·unity·图形渲染·three.js·unreal engine
zh_xuan3 小时前
api调试工具增加支持输入请求头
c++·libcurl
纽扣6673 小时前
【算法进阶之路】链表核心:快慢指针与反转链表专题精讲
数据结构·c++·算法·链表
格林威3 小时前
工业视觉检测:两大主流异常检测开源框架深度对比(PatchCore vs SPADE)
开发语言·人工智能·深度学习·数码相机·计算机视觉·视觉检测·工业相机
lzh200409193 小时前
Linux管道(Pipe)深度指南:从原理到实战
linux·c++
eDEs OLDE3 小时前
CC++链接数据库(MySQL)超级详细指南
c语言·数据库·c++
2zcode3 小时前
基于Matlab元胞自动机模拟(CA)静态再结晶过程
开发语言·matlab·静态再结晶
浅念-3 小时前
吃透栈:LeetCode 栈算法题全解析
数据结构·c++·算法·leetcode·职场和发展·
NQBJT3 小时前
双轮足导盲机器人:多传感融合与全局-局部分层导航系统设计
c++·esp32·openmv·避障·导盲·轮足