C 动态新闻推送 第63期
文章
- Did you know that C 23 added Literal Suffix for (signed) size_t?
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