C++ 中文周刊 第46期

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

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

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


资讯

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

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

文章

int main() {
    using namespace std;
    variant<string, bool> var{"im-a-string"};
    if (holds_alternative<string>(var)) {
        cout << "string value is: " << get<string>(var) << endl; // GCC > 9.4
    } else if (holds_alternative<bool>(var)) {
        cout << "bool value is: " << get<bool>(var) << endl;  // GCC <= 9.4
    } else {
        abort();
    }
}

在旧的gcc版本会打印bool

主要原因是这个构造语意存在问题p0608r3 这个提案就是解决这个问题

#include <functional>

int main() {
  {
  std::function<int()> f{[]{return 42; }};
  auto copy = f; // okay
  auto value = f();
  }

  {
  std::move_only_function<int()> f{[] {return 42; }};
  auto copy = f; // error, call to deleted copy constructor
  auto value = f(); // undefined behaviour, dandling reference
  }
}

终于进c++了,叫move_only_function

concept限制的auto

void signedIntsOnly(SignedIntegral auto val) { }
void floatsOnly(std::floating_point auto fp) { }

//等价
template <SignedIntegral T>
void signedIntsOnly(T val) { }

template <std::floating_point T>
void floatsOnly(T fp) { }

比较泛化的lambda

auto fn = []<typename T>(vector<T> const& vec) { 
    cout << size(vec) << ,  << vec.capacity(); 
};

尽可能的constexpr

#include <numeric>

constexpr int naiveSum(unsigned int n) {
    auto p = new int[n];
    std::iota(p, p+n, 1);
    auto tmp = std::accumulate(p, p+n, 0);
    delete[] p;
    return tmp;
}

constexpr int smartSum(unsigned int n) {
    return (1+n)*(n/2);
}

int main() {
    static_assert(naiveSum(10) == smartSum(10));
    return 0;
}

Using enum 简单化代码

#include <iostream>

enum class long_enum_name { hello, world, coding };

void func(long_enum_name len) {
#if defined(__cpp_using_enum) // c++20 feature testing
    switch (len) {
        using enum long_enum_name;
        case hello: std::cout << "hello "; break;
        case world: std::cout << "world "; break;
        case coding: std::cout << "coding "; break;
    }
#else
    switch (len) {
        case long_enum_name::hello: std::cout << "hello "; break;
        case long_enum_name::world: std::cout << "world "; break;
        case long_enum_name::coding: std::cout << "coding "; break;
    }
#endif
}

enum class another_long_name { hello, breaking, code };

int main() {
    using enum long_enum_name;
    func(hello);
    func(coding);
    func(world);
    
// using enum another_long_name; // error: 'another_long_name::hello' 
                             // conflicts with a previous declaration
}

复杂的NTTP (不过很少用得到)

#include <iostream>

struct Constants {
    double gravityAcceleration_ { 1.0 };

    constexpr double getGA() const { return gravityAcceleration_;}
};

template <Constants C>
double ComputeWeight(double mass) {
    return mass * C.getGA();
}

int main() {
    constexpr Constants EarthGa { 9.81 };
    constexpr Constants MoonGa { 1.625 };
    std::cout << ComputeWeight<EarthGa>(70.0) << '\n';
    std::cout << ComputeWeight<MoonGa>(70.0) << '\n';
}

位域初始化

#include <iostream>

struct Type {
    int value : 4 = 1;
    int second : 4 { 2 };
};

int main() {
    Type t;
    std::cout << t.value << '\n';
    std::cout << t.second << '\n';
}

c的字段构造

struct Point { double x; double y; };
Point p { .x = 10.0, .y = 20.0 };

nodiscard带信息

[[nodiscard("Don't call this heavy function if you don't need the result!")]]
bool Compute();

rangefor结合初始化,这也是之前提到过的range-for的缺陷问题,有了新的解决方案

//for (init; decl : expr)
for (auto& x : foo().items()) { /* .. */ } // 生命周期问题,不能这么搞
for (T thing = foo(); auto& x : thing.items()) { /* ... */ } // OK

consteval, 深度优化成立即数

consteval int sum(int a, int b) {
  return a + b;
}

constexpr int sum_c(int a, int b) {
    return a + b;
}

int main() {
    constexpr auto c = sum(100, 100);
    static_assert(c == 200);

    constexpr auto val = 10;
    static_assert(sum(val, val) == 2*val);

    int a = 10;
    int b = sum_c(a, 10); // fine with constexpr function

    // int d = sum(a, 10); // error! the value of 'a' is 
                           // not usable in a constant expression
}

看这段代码

int main() {
    int isAdmin = 0;
    /*‮ } ⁦if (isAdmin)⁩ ⁦ begin admins only */
        __builtin_printf("You are an admin.\n");
    /* end admins only ‮ { ⁦*/
    return 0;
}

这些特殊字符 gcc12会告警。所以后面的代码不会生效

讨论c++ repl交互的进展,一些实现,比如julia cling等等 (这玩意真的有人用吗)

有了consteval和fmtlib,代码更好写了

以前的代码

constexpr ErrorToMessage error_to_message[] = {
    { C2000, fetch_message(C2000) },
    { C2001, fetch_message(C2001) },
    ...
};

template <typename... Ts>
constexpr bool are_arguments_valid(ErrorNumber n) {
    /* 1. fetch message
       2. parse specifiers
       3. check each specifier against the parameter pack Ts... */
    return result;
}

template <typename... Ts>
void error(ErrorNumber n, Ts&&... ts) {
    assert(are_arguments_valid<Ts...>(n));
    /* do error stuff */
}

现在的代码

#include <string_view>
#include <type_traits>

// Exposition only
#define FAIL_CONSTEVAL throw

template <typename T>
struct Checker {
    consteval Checker(const char* fmt) {
        if (fmt != std::string_view{ "valid" }) // #1
            FAIL_CONSTEVAL;
        // T must be an int
        if (!std::is_same_v<T, int>)            // #2
            FAIL_CONSTEVAL;
    }
};

template <typename T>
void fmt(std::type_identity_t<Checker<T>> checked, T);

int main() {
    fmt("valid", 10);    // compiles
    fmt("oops", 10);     // fails at #1
    fmt("valid", "foo"); // fails at #2
}

consteval能编译期就把不合法的使用找出来

视频

介绍这个有量纲计算的库https://github.com/mpusz/units 编译期计算

开源项目需要人手

新项目介绍/版本更新

[library]
name = "toml++"
authors = ["Mark Gillard <mark.gillard@outlook.com.au>"]

[dependencies]
cpp = 17

工作招聘

暂无推荐


本文永久链接

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