C++ 动态新闻推送 第46期

2022-01-19 16:12:59 浏览数 (1)

C 动态新闻推送 第46期

文章

  • 一个variant bug
代码语言:javascript复制
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 这个提案就是解决这个问题

  • c tip of week 260 Did you know that C 23 added std::move_only_function?

这个就是c 14-c 17那会社区一直念叨的function_ref function_view,一个轻量的function

代码语言:javascript复制
#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

  • c 20 十个典型代码段

concept限制的auto

代码语言:javascript复制
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

代码语言:javascript复制
auto fn = []<typename T>(vector<T> const& vec) { 
    cout << size(vec) << “, “ << vec.capacity(); 
};

尽可能的constexpr

代码语言:javascript复制
#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 简单化代码

代码语言:javascript复制
#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 (不过很少用得到)

代码语言:javascript复制
#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';
}

位域初始化

代码语言:javascript复制
#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的字段构造

代码语言:javascript复制
struct Point { double x; double y; };
Point p { .x = 10.0, .y = 20.0 };

nodiscard带信息

代码语言:javascript复制
[[nodiscard("Don't call this heavy function if you don't need the result!")]]
bool Compute();

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

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

consteval, 深度优化成立即数

代码语言:javascript复制
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
}
  • Prevent Trojan Source attacks with GCC 12

看这段代码

代码语言:javascript复制
int main() {
    int isAdmin = 0;
    /*‮ } ⁦if (isAdmin)⁩ ⁦ begin admins only */
        __builtin_printf("You are an admin.n");
    /* end admins only ‮ { ⁦*/
    return 0;
}

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

  • C Language Interoperability Layer

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

  • How we used C 20 to eliminate an entire class of runtime bugs

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

以前的代码

代码语言:javascript复制
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 */
}

现在的代码

代码语言:javascript复制
#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能编译期就把不合法的使用找出来

视频

  • Daniel Withopf - Physical Units for Matrices. How hard can it be? - Meeting C 2021

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

新项目介绍/版本更新

  • oatpp 1.3.0发布,一个网络库
  • json bugfix
  • SObjectizer 一个actor库
  • 用 C 14 写了个模糊查找命令行工具
  • toml 性能提升30% toml是一种配置文件格式,ini和yaml结合的感觉。rust的cargo包管理用的就是这个格式
代码语言:javascript复制
[library]
name = "toml  "
authors = ["Mark Gillard <mark.gillard@outlook.com.au>"]

[dependencies]
cpp = 17
  • SecretHandshake secure connections for Cap’n Proto RPC 一个rpc server 这个协议不知道干嘛的
  • self_macro 感觉是一个type map实现,但是不知道有啥用
  • veque vector deque 点子有点意思,有点ringbuffer的感觉

0 人点赞