【Modern C++】现代魔法笔记

3 篇文章 0 订阅

简单记录一下近期学习的一些魔法,

有些魔法会需要c++20才能用,编译的时候建议直接开c++20,

std::move, std::forward

右值引用、完美转发啥的,神奇玩意,还没完全搞懂,

constexpr

const的进阶版,可以用来修饰变量,函数,lambda表达式,
告诉编译器这是一个可以在编译器计算的东西,这样在编译器即可计算,无需等到运行期,
配合static_assert可以做到编译时自定义报错。示例代码见std::index_sequence的示例代码;

这个还能用在if后面做编译期的条件判断,

if constexpr () {};

Attention

要注意编译期的计算是很慢的(慢10倍左右),并且有计算总次数限制,可以使用编译开关-fconstexpr-ops-limit=来自定义,

在多文件编译的场景下,每个.cpp的constexpr是相互独立的,也就是每个cpp有着单独的constexpr-ops-limit,并且同一个.h中的同一个constexpr在不同的.cpp会被重复计算多次,哪怕最终运行期的地址相同。

std::index_sequence

在编译期的整数序列,和std::make_index_sequence配合使用,在编译期生成整数数列。

最简单的用法:

template <size_t... idx>
auto IdxSeq(std::index_sequence<idx...>)
{
    return std::array{idx...};
}
auto idxSeq = IdxSeq(std::make_index_sequence<5>{});
// idxSeq = {0, 1, 2, 3, 4}

比较好的完整讲解:C++雾中风景16:std::make_index_sequence, 来试一试新的黑魔法吧

接下来是一个大杂烩代码:

Code

#include <array>
#include <iostream>
#include <cassert>

constexpr int MAXN = 3;

template <size_t... N>
static constexpr auto GeneI(std::index_sequence<N...>)
{
    constexpr int n = sizeof...(N);
    // tamplate for labmda was allowed after c++20
    auto GeneJ = []<size_t... M>(int line, std::index_sequence<M...>) constexpr
    {
        return std::array{int((n * line + M))...};
    };
    return std::array{GeneJ(N, std::make_index_sequence<n>{})...};
}

constexpr auto a = GeneI(std::make_index_sequence<MAXN>{});
// equivalent :
constexpr std::array<std::array<int, MAXN>, MAXN>
    a1 = {{{0, 1, 2}, {3, 4, 5}, {6, 7, 8}}};

int main(int argc, char *argv[])
{
    static_assert(a[0][0]); // compile error: static assertion failed
    static_assert(a[0][1]); // OK
}

template <typename… Args>

可变模版参数的展开,在编译期完成,

典型用法是做参数转发:

template <typename... Args>
auto func1(Args &&...args)
{
    return func2(std::forward<Args>(args)...);
}

还可以用来做可变入参数量的函数:

template <typename... Args>
auto sum(Args &&...args) { return (... + args); }

sum(1, .5, true); // 2.5 
sum(std::string("aa"), "bb"); // "aabb"

折叠表达式

上面示例代码用的... +就是折叠表达式的一种,

理解不难,见官方文档:
cppreference.com - fold expression

改Class中的Private成员

我看不懂,但我大受震撼

#include <iostream>
#include <stdint.h>
using namespace std;

class Bank {
public:
    void Check()
    {
        cout << "bank: " << money << endl;
    }

private:
    size_t money = 1100;
};

template <auto M>
struct Tunnel;

template <typename T, typename U, T U::*M>
struct Tunnel<M> {
    friend T& Sneak(U& u)
    {
        return u.*M;
    }
};

template struct Tunnel<&Bank::money>;
size_t& Sneak(Bank&);

int main()
{
    Bank bank;
    bank.Check();

    auto& takeCtl = Sneak(bank);
    cout << "theif: " << takeCtl << endl;

    takeCtl = 0;
    bank.Check();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值