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

2022-05-27 15:47:35 浏览数 (1)

C 动态新闻推送 第63期

文章

  • Did you know that C 23 added Literal Suffix for (signed) size_t?
代码语言:javascript复制
static_assert(-42 == -42z);
static_assert(-42 == -42Z);
static_assert(42 == 42uz);
static_assert(42 == 42uZ);
static_assert(42 == 42Uz);
static_assert(42 == 42ZU);
static_assert(42 == 42Zu);

static_assert(std::is_same_v<std::size_t, decltype(42uz)>);

没啥说的。别的语言都有的,早该加加了

  • Writing a sort comparison function, part 1: basics

比较函数很容易想到用tuple简化

代码语言:javascript复制
// three-way comparison
int compare_3way_for_sorting(T const& a, T const& b)
{
    int a_key = key(a);
    ant b_key = key(b);

    if (a_key < b_key) return -1;
    if (a_key > b_key) return  1;
    return 0;
}

// less-than comparison
bool compare_less_for_sorting(T const& a, T const& b)
{
    return key(a) < key(b);
}

This reduces the problem to writing a sort key. Here’s an example:

// Key generator: Sort by total cost (price   tax)
auto key(T const& t)
{
    return t.price   t.tax;
}

For a multi-level sort, you can return a std::pair or std::tuple with the most significant key as the first element.

// Key generator: Sort by length, then by width
auto key(T const& t)
{
    return std::make_pair(t.length, t.width);
}

// Key generator: Sort by length, then by width,
// then by weight
auto key(T const& t)
{
    return std::make_tuple(t.size, t.width, t.weight);
}

tuple的问题是值,拷贝太重,可能想到ref

代码语言:javascript复制
auto key(T const& t)
{
    return std::make_tuple(std::ref(t.name), t.age);
}

或者用forward_as_tuple

代码语言:javascript复制
auto key(T const& t)
{
    return std::forward_as_tuple(t.name, t.age);
}

问题在与forward_as_tuple拿的是引用,所以如果你传右值就完了,除非生命周期就一行

代码语言:javascript复制
auto key(T const& t)
{
    return std::forward_as_tuple(t.name, t.height * t.width);
}

这样不行,第二个值在外面很有可能乱了

代码语言:javascript复制
bool compare_less_for_sorting(T const& a, T const& b)
{
    return std::forward_as_tuple(a.name, a.height * a.width) <
     std::forward_as_tuple(b.name, b.height * b.width);
}

这样可以,生命周期就一行,比较完了就扔掉

一般来说,要传出去当个lambda,只好用tuple ref

代码语言:javascript复制
bool compare_less_for_sorting(T const& a, T const& b)
{
    auto key = [](auto&& t) {
        return std::make_tuple(std::ref(t.name), t.height * t.width);
    };
    return key(a) < key(b);
}


void f(std::vector<T>& v)
{
    auto key = [](auto&& t) {
        return std::make_tuple(std::ref(t.name), t.height * t.width);
    };
    std::sort(v.begin(), v.end(), [key](auto&& t, auto&& b) {
        return key(a) < key(b);
    });
}

当然,也可以不用tuple,一个字段一个字段来解

代码语言:javascript复制
int compare_3way_for_sorting(T const& a, T const& b)
{
    // First compare by name
    if (a.name < b.name) return -1;
    if (a.name > b.name) return  1;

    // Names are equal, check connector names
    auto&& a_connector = a.GetConnector();
    auto&& b_connector = b.GetConnector();

    if (a_connector.name < b_connector.name) return -1;
    if (a_connector.name > b_connector.name) return  1;

    // Names and connector names are equal,
    // check manufacturing date
    auto&& a_date = LookupManufacturingDate(a.part_number);
    auto&& b_date = LookupManufacturingDate(b.part_number);

    if (a_date < b_date) return -1;
    if (a_date > b_date) return  1;

    // All keys match
    return 0;
}

// less-than comparison
bool compare_less_for_sorting(T const& a, T const& b)
{
    // First compare by name
    if (a.name < b.name) return true;
    if (a.name > b.name) return false;

    // Names are equal, check connector names
    auto&& a_connector = a.GetConnector();
    auto&& b_connector = b.GetConnector();

    if (a_connector.name < b_connector.name) return true;
    if (a_connector.name > b_connector.name) return false;

    // Names and connector names are equal,
    // check manufacturing date
    auto&& a_date = LookupManufacturingDate(a.part_number);
    auto&& b_date = LookupManufacturingDate(b.part_number);

    if (a_date < b_date) return true;
    if (a_date > b_date) return false;

    // All keys match
    return false;
}

用auto&&触发完美转发,肯定没损失

接着tuple方案进阶一下,如果我们想要定制比较,让比较的这个函数可变,且不传多个lambda

代码语言:javascript复制
template<typename Lambda>
struct defer_comparison
{    
    defer_comparison(Lambda lambda) : key(std::move(lambda)){}
    Lambda key;

    auto operator<=>(defer_comparison const& other) const
        { return compare_3way(key(), other.key() ); }
};
 
auto key(T const& t)
{
    return std::make_tuple(std::ref(t.name),
                          defer_comparison([&] { return t.GetConnector(); }),
                          defer_comparison([&] { return LookupManufacturingDate(t.part_number); }));
}

std::weak_ordering
compare_3way_for_sorting(T const& a, T const& b)
{
    return key(a) <=> key(b);
}

bool compare_less_for_sorting(T const& a, T const& b)
{
    return key(a) < key(b);
}


bool compare_less_for_sorting(T const& a, T const& b)
{
    auto a_tuple = key(a);
    auto b_tuple = key(b);

    if (std::get<0>(a) < std::get<0>(b)) return true;
    if (std::get<0>(a) > std::get<0>(b)) return false;

    if (std::get<1>(a) < std::get<1>(b)) return true;
    if (std::get<1>(a) > std::get<1>(b)) return false;

    if (std::get<2>(a) < std::get<2>(b)) return true;
    if (std::get<2>(a) > std::get<2>(b)) return false;

    return false;
}

当然这种在c 20有更好的写法

代码语言:javascript复制
// three-way comparison
std::weak_ordering
compare_3way_for_sorting(T const& a, T const& b)
{
    // First compare by name
    std::weak_ordering cmp = a.name <=> b.name;
    if (cmp != 0) return cmp;

    // Names are equal, check connector names
    cmp = a.GetConnector() <=> b.GetConnector();
    if (cmp != 0) return cmp;

    // Names and connector names are equal,
    // manufacturing date is the last check.
    cmp = LookupManufacturingDate(a.part_number) <=>
          LookupManufacturingDate(b.part_number);
    return cmp;
}

// less-than comparison
bool compare_less_for_sorting(T const& a, T const& b)
{
    // First compare by name
    std::weak_ordering cmp = a.name <=> b.name;
    if (cmp != 0) return cmp < 0;

    // Names are equal, check connector names
    cmp = a.GetConnector() <=> b.GetConnector();
    if (cmp != 0) return cmp < 0;

    // Names and connector names are equal,
    // manufacturing date is the last check.
    cmp = LookupManufacturingDate(a.part_number) <=>
          LookupManufacturingDate(b.part_number);
    return cmp < 0;
}

或者

代码语言:javascript复制
// three-way comparison
std::weak_ordering
compare_3way_for_sorting(T const& a, T const& b)
{
    std::weak_ordering cmp = a.name <=> b.name;
    if (cmp == 0) cmp = a.GetConnector() <=> b.GetConnector();
    if (cmp == 0) cmp = LookupManufacturingDate(a.part_number) <=>
                        LookupManufacturingDate(b.part_number);
    return cmp;
}

// less-than comparison
bool compare_less_for_sorting(T const& a, T const& b)
{
    // First compare by name
    std::weak_ordering cmp = a.name <=> b.name;
    if (cmp == 0) cmp = a.GetConnector() <=> b.GetConnector();
    if (cmp == 0) cmp = LookupManufacturingDate(a.part_number) <=>
                        LookupManufacturingDate(b.part_number);
    return cmp < 0;
}

也可以有保底策略

代码语言:javascript复制
std::weak_ordering
compare_3way_for_sorting(T const& a, T const& b)
{
    auto cmp = std::compare_weak_order_fallback(a.name, b.name);
    if (cmp == 0) cmp = std::compare_weak_order_fallback(a.GetConnector(), b.GetConnector());
    if (cmp == 0) cmp = std::compare_weak_order_fallback(LookupManufacturingDate(a.part_number),
                                                         LookupManufacturingDate(b.part_number));
    return cmp;
}

// less-than comparison
bool compare_less_for_sorting(T const& a, T const& b)
{
    auto cmp = std::compare_weak_order_fallback(a.name, b.name);
    if (cmp == 0) cmp = std::compare_weak_order_fallback(a.GetConnector(), b.GetConnector());
    if (cmp == 0) cmp = std::compare_weak_order_fallback(LookupManufacturingDate(a.part_number),
                                                         LookupManufacturingDate(b.part_number));
    return cmp < 0;
}
  • Avoid exception throwing in performance-sensitive code 异常影响性能
  • How to Store an lvalue or an rvalue in the Same Object

如何同时保存lvalue和rvalue,你可能会想到variant,但是 variant是不支持存饮用的,所以只能猥琐路线

代码语言:javascript复制
template<typename T>
struct NonConstReference
{
    T& value_;
    explicit NonConstReference(T& value) : value_(value){};
};

template<typename T>
struct ConstReference
{
    T const& value_;
    explicit ConstReference(T const& value) : value_(value){};
};

template<typename T>
struct Value
{
    T value_;
    explicit Value(T&& value) : value_(std::move(value)) {}
};

template<typename T>
using Storage = std::variant<Value<T>, ConstReference<T>, NonConstReference<T>>;


template<typename... Functions>
struct overload : Functions...
{
    using Functions::operator()...;
    overload(Functions... functions) : Functions(functions)... {}
};

template<typename T>
T const& getConstReference(Storage<T> const& storage)
{
    return std::visit(
        overload(
            [](Value<T> const& value) -> T const&             { return value.value_; },
            [](NonConstReference<T> const& value) -> T const& { return value.value_; },
            [](ConstReference<T> const& value) -> T const&    { return value.value_; }
        ),
        storage
    );
}


class MyClass
{
public:
    explicit MyClass(std::string& value) :       storage_(NonConstReference(value)){}
    explicit MyClass(std::string const& value) : storage_(ConstReference(value)){}
    explicit MyClass(std::string&& value) :      storage_(Value(std::move(value))){}

    void print() const
    {
        std::cout << getConstReference(storage_) << 'n';
    }

private:
    Storage<std::string> storage_;
};
  • Concepts Error Messages for Humans

笑死。concept编译相关报错太离谱有人写提案建议标准优化这里

  • Optimizing your QML application for compilation to C

qt profile教程,减少编译时间

  • Check Types with Concepts

作者实现了个函数能检测构造函数支持,bigsix

代码语言:javascript复制
#include <algorithm>
#include <iostream>
#include <type_traits>

template<typename T>
struct isBigSix: std::integral_constant<bool,
                                      std::is_default_constructible<T>::value &&
                                      std::is_copy_constructible<T>::value &&
                                      std::is_copy_assignable<T>::value &&
                                      std::is_move_constructible<T>::value &&
                                      std::is_move_assignable<T>::value &&
                                      std::is_destructible<T>::value>{};

当然,标准库已经有类似的东西了std::semiregular std::regular

这里作者讨论了一个问题,is_move_constructible并不表明这个类会move,也可能是copy 退化的

代码语言:javascript复制
template<typename T>
concept BigSix = isBigSix<T>::value;

template <BigSix T>                                   
void swap(T& a, T& b) noexcept {
    T tmp(std::move(a));
    a = std::move(b);
    b = std::move(tmp);
}

struct MyData{                                        
    MyData() = default;
    MyData(const MyData& ) {
        std::cout << "copy constructorn";
    }
    MyData& operator=(const MyData& m) {
        std::cout << "copy assignment operatorn";
        return *this;
    }

};

int main(){
    MyData a, b;
    swap(a, b);       
    static_assert(BigSix<MyData>, "BigSix not supported");                             
}
//copy constructor
//copy assignment operator
//copy assignment operator

编译不会报错。调用swap的时候调用的是MyData的拷贝构造, 看cppreference文档

注解 无移动构造函数的但有接受 const T& 参数的复制构造函数的类型,满足 std::is_move_constructible

  • C 20 Ranges Algorithms - 11 Modifying Operations

介绍range api rotate reverse replace remove 没啥说的

视频

  • C Weekly - Ep 324 - C 20’s Feature Test Macros

介绍测试宏的。__cpp_lib_xx

Pure Virtual C 2022 Recordings Available

大部分都是工具相关,没啥说的

  • Indexed Find in Files

介绍VS的查找功能如何索引文件

就给了个图,实现细节啥也没说

  • Cute C Tricks, Part 2 of N: More code you should learn from and never write

constexpr里不能用static_assert但能用assert,为啥?

她说了一大堆,我没怎么听懂,没字幕

新项目介绍/版本更新

  • Experimental concurrency 线程相关的压测数据
  • Nystrom’s Crafting Interpreters: An Implementation in C 说实话我一直想写一个来着,这个确实有意思
  • Protocol Puffers: A little, highly templated, and protobuf-compatible serialization/deserialization library written in C 20

这个是国人项目

  • sobjectizer 5.74 一个actor
  • Catch2 3.01
  • vcpkg May 2022 Release: artifacts using JSON, COS and SPDX support, and more

0 人点赞