C++ 中文周刊 第52期

reddit/hackernews/lobsters/meetingcpp摘抄一些c++动态

周刊项目地址在线地址知乎专栏 腾讯云+社区

欢迎投稿,推荐或自荐文章/软件/资源等,请提交 issue


资讯

标准委员会动态/ide/编译器信息放在这里

编译器信息最新动态推荐关注hellogcc公众号 本周更新 2022-03-02 第139期

文章

数字转字符串 sprintf性能,非常垃圾,使用fmt或者std::to_chars

namespace adl {
    struct foo {};
    void bar(foo) {}
}

int main() {
    adl::foo foo;
    bar(foo);   // OK,    ADL
    (bar)(foo); // error: no ADL
}

就是名字空间内的查找

#include <utility>

int main() {
    std::unreachable();
    return 42; // invokes undefined behavior
}

没啥说的,类似assert(false)

int main() {
  std::vector v{1, 2, 3, 4};
  assert(4 == std::size(v));
  std::erase_if(v, [](const auto& e) { return e % 2;} );
  assert(2 == std::size(v));
  assert(v[0] == 2 and v[1] == 4);
}

没啥说的

手把手教你图像过滤,看不懂

图像sample 看不懂

手把手教你gmock

几个需求,编译期打印字符串,编译期生成随机数 第一个简单,就是fixed_string+static assert

struct ct_str
{
    char        _data[512]{};
    std::size_t _size{0};

    template <std::size_t N>
    constexpr ct_str(const char (&str)[N]) : _data{}, _size{N - 1}
    {
        for(std::size_t i = 0; i < _size; ++i)
            _data[i] = str[i];
    }
};

template <ct_str> struct print;

constexpr ct_str test()
{
    ct_str s{"Welcome to Wordlexpr!"};
    s._data[0] = 'w';
    s._data[11] = 'w';
    s._data[20] = '.';
    return s;
}

print<test()> _{};

第二个就是用fixed_string来做生成随机数的生成器,让外部指定seed和字符串,然后编译的时候改一改就行了

语言律师新活,如果itor是T*,会有一大堆冲突问题,后面是一大堆列举。这里不提了

感谢@LH_Mouse 纠正。这里指的是是实现的不可见导致的开销。实现的不可见(不内联场景),编译器可能假定抛出异常,假定不是const。所以这里不是zero cost。即使你不用异常也会有类似的问题

c++编译依赖和头文件的问题。属于老生常谈的讨论

google benchmark教程,几个案例

基本的阻止优化

static void i32_addition_semirandom(bm::State &state) {
    int32_t a = std::rand(), b = std::rand(), c = 0;
    for (auto _ : state)
        bm::DoNotOptimize(c = (++a) + (++b));
}

一个简单的数学算法对比

static void f64_sin(bm::State &state) {
    double argument = std::rand(), result = 0;
    for (auto _ : state)
        bm::DoNotOptimize(result = std::sin(argument += 1.0));
}

static void f64_sin_maclaurin(bm::State &state) {
    double argument = std::rand(), result = 0;
    for (auto _ : state) {
        argument += 1.0;
        result = argument - std::pow(argument, 3) / 6 + std::pow(argument, 5) / 120;
        bm::DoNotOptimize(result);
    }
}
static void f64_sin_maclaurin_powless(bm::State &state) {
    double argument = std::rand(), result = 0;
    for (auto _ : state) {
        argument += 1.0;
        result = argument - (argument * argument * argument) / 6.0 +
                 (argument * argument * argument * argument * argument) / 120.0;
        bm::DoNotOptimize(result);
    }
}

[[gnu::optimize("-ffast-math")]]
static void f64_sin_maclaurin_with_fast_math(bm::State &state) {
    double argument = std::rand(), result = 0;
    for (auto _ : state) {
        argument += 1.0;
        result = argument - (argument * argument * argument) / 6.0 +
                 (argument * argument * argument * argument * argument) / 120.0;
        bm::DoNotOptimize(result);
    }
}

注意这个attrbute用法。最后一种非常快

整数除法

static void i64_division(bm::State &state) {
    int64_t a = std::rand(), b = std::rand(), c = 0;
    for (auto _ : state)
        bm::DoNotOptimize(c = (++a) / (++b));
}

static void i64_division_by_const(bm::State &state) {
    int64_t money = 2147483647;
    int64_t a = std::rand(), c;
    for (auto _ : state)
        bm::DoNotOptimize(c = (++a) / *std::launder(&money));
}
static void i64_division_by_constexpr(bm::State &state) {
    constexpr int64_t b = 2147483647;
    int64_t a = std::rand(), b;
    for (auto _ : state)
        bm::DoNotOptimize(c = (++a) / b);
}

constexpr非常快

硬件加速

[[gnu::target("default")]] static void u64_population_count(bm::State &state) {
    auto a = static_cast<uint64_t>(std::rand());
    for (auto _ : state)
        bm::DoNotOptimize(__builtin_popcount(++a));
}
[[gnu::target("popcnt")]] static void u64_population_count_x86(bm::State &state) {
    auto a = static_cast<uint64_t>(std::rand());
    for (auto _ : state)
        bm::DoNotOptimize(__builtin_popcount(++a));
}

如果硬件支持popcnt指令,有优化提升

里面有个表格概括,就不截图了

视频

还是模板 + fixed_string/array 这种场景,如果fixed_string/array是相同的,由于模板实例化相同的实例会合并,所以说这就是一种压缩效果,复用数据段。

就是static assert + type traits没啥说的

又介绍个parser generator

开源项目需要人手


本文永久链接

看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持! 觉得写的不错那就给点吧, 在线乞讨 微信转账