公众号
RSS https://github.com/wanghenshui/cppweeklynews/releases.atom
欢迎投稿,推荐或自荐文章/软件/资源等
这周瞎忙一周,没来得及看
标准委员会动态/ide/编译器信息放在这里
编译器信息最新动态推荐关注hellogcc公众号 本周更新 2023-03-08 第192期
TL;DR 使用enable_shared_from_this
一定要public继承
一波源码解读,brpc大家都懂懂,争取抄一个自己的rpc
空大讲execution的文章,感兴趣的看看
Daniel Lemire我觉得他的名字应该没人不知道吧。已经提及过很多次,性能专家
std::from_chars
已经要比strtod
快很多倍了,作者的fast_float
比std::from_chars
还快
(前身是fast_double_parser,没切的建议切过去,API和std::from_chars
相同)
这篇文章是案例顺带压测一下速度。不用看也知道是吊锤,这个库很多软件都用,比如clickhouse
就是SIMD 接口。没啥说的
#include <immintrin.h>
int main() {
const std::vector a = {1, 2, 3, 4};
const std::vector b = {5, 6, 7, 8};
const auto va = _mm_loadu_si128((__m128i*)a.data());
const auto vb = _mm_loadu_si128((__m128i*)b.data());
const auto result = _mm_add_epi32(va, vb);
std::vector<int> v(a.size());
_mm_storeu_si128((__m128i*)v.data(), result);
assert((std::vector{1 + 5, 2 + 6, 3 + 7, 4 + 8} == v));
}
讲trivial relocation的现状以及开源实现
T.r. types | Non-t.r. types | Throwing-move types | Rightward motion (`insert`) | Leftward motion (`erase`) | Non-pointer iterators | ||
STL Classic (non-relocating) | std::copy | N/A | N/A | ✓ | UB | ✓ | ✓ |
std::copy_n | N/A | N/A | ✓ | UB | UB | ✓ | |
std::copy_backward | N/A | N/A | ✓ | ✓ | UB | ✓ | |
cstring | memcpy | ✓ | UB | ✓ | UB | UB | SFINAE |
memmove | ✓ | UB | ✓ | ✓ | ✓ | SFINAE | |
Qt | q_uninitialized_relocate_n | ✓ | ✓ | ✓? | UB | UB | SFINAE |
q_relocate_overlap_n | ✓ | ✓ | ✓ | ✓ | ✓ | SFINAE | |
BSL | destructiveMove | ✓ | ✓ | ✓ | UB | UB | SFINAE |
P2786R0 | trivially_relocate | ✓ | SFINAE | SFINAE | ✓ | ✓ | SFINAE |
relocate | ✓ | ✓ | SFINAE | ✓ | ✓ | SFINAE | |
move_and_destroy | ✓ | ✓ | SFINAE | UB | ? | ✓ | |
P1144R6 | uninitialized_relocate | ✓ | ✓ | ✓ | UB | ✓ | ✓ |
uninitialized_relocate_n | ✓ | ✓ | ✓ | UB | ✓ | ✓ | |
P1144R7 | uninitialized_relocate_backward | ✓ | ✓ | ✓ | ✓ | UB | ✓ |
还给人folly提MR https://github.com/facebook/folly/pull/1934
这是个挺复杂的话题。了解一波
还是和trivial relocation相关的实现问题。看不懂
一些模版技巧介绍
CRTP没人不知道吧,想想enable_shared_from_this
overload用法,也就这么个例子
template<typename ... Ts>
struct Overload : Ts ... {
using Ts::operator() ... ;
};
策略模版,比如
template<class T, class Allocator std::allocator<T>>
class vector;
template<class Key,
class T,
class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class allocator = std::allocator<std::pair<const Key, T>>
class unordered_map;
Tag Dispatching 想想迭代器特化
Type Erasure 想想std::function
,之前咱们也手挫过一个,往前翻翻回忆一下
先列一段装饰器模式的代码,其实就是策略模式
// taxed.h
#pragma once
#include "money.h"
#include "priced_item.h"
#include <utility>
template< int taxRate, PricedItem Item >
class Taxed : private Item // Using inheritance
{
public:
template< typename... Args >
explicit Taxed( Args&&... args )
: Item{ std::forward<Args>(args)... }
{}
Money price() const {
return Item::price() * ( 1.0 + (taxRate/100) );
}
};
// priced_item.h
#pragma once
#include "money.h"
template< typename T >
concept PricedItem =
requires ( T item ) {
{ item.price() } -> std::same_as<Money>;
};
// money.h
#pragma once
#include <cmath>
#include <concepts>
#include <cstdint>
#include <ostream>
struct Money
{
uint64_t value{};
};
template< typename T >
requires std::is_arithmetic_v<T>
Money operator*( Money money, T factor )
{
return Money{ static_cast<uint64_t>( money.value * factor ) };
}
constexpr Money operator+( Money lhs, Money rhs ) noexcept
{
return Money{ lhs.value + rhs.value };
}
std::ostream& operator<<( std::ostream& os, Money money )
{
return os << money.value;
}
// discounted.h
#pragma once
#include "money.h"
#include "priced_item.h"
#include <utility>
template< int discount, PricedItem Item >
class Discounted // Using composition
{
public:
template< typename... Args >
explicit Discounted( Args&&... args )
: item_{ std::forward<Args>(args)... }
{}
Money price() const {
return item_.price() * ( 1.0 - (discount/100) );
}
private:
Item item_;
};
// cpp_book.h
#pragma once
#include "money.h"
#include <string>
#include <utility>
class CppBook
{
public:
CppBook( std::string name, Money price )
: name_{ std::move(name) }
, price_{ price }
{}
std::string const& name() const { return name_; }
Money price() const { return price_; }
private:
std::string name_;
Money price_;
};
// main.cpp
#include "conference_ticket.h"
#include "cpp_book.h"
#include "discounted.h"
#include "taxed.h"
#include <cstdlib>
int main()
{
// 20% discount, 15% tax: (499*0.8)*1.15 = 459.08
Taxed<15,Discounted<20,ConferenceTicket>> item{ "Core C++", Money{499} };
Taxed<16,Discounted<21,ConferenceTicket>> item2{ "Core C++", Money{499} };
Taxed<17,Discounted<22,CppBook>> item3{ "Core C++", Money{499} };
Money const totalPrice = item.price(); // Results in 459.08
Money const totalPrice2 = item2.price();
Money const totalPrice3 = item3.price();
// ...
return EXIT_SUCCESS;
}
比继承快多了
MSVC的能力介绍
chrome编译符号太大了。只能升级工具来解决这个问题。作者的吐槽文
组合函数,高阶函数,一个常规的写法
template <class F, class... Fs>
constexpr auto compose(F &&arg, Fs &&...args) {
return [
fun = std::forward<F>(arg),
... functions = std::forward<Fs>(args)
] <class... Xs> (Xs &&...xs) mutable
requires std::invocable<F, Xs...> {
if constexpr (sizeof...(Fs)) {
return compose(std::forward<Fs>(functions)...)(
std::invoke(std::forward<F>(fun),
std::forward<Xs>(xs)...));
} else {
return std::invoke(
std::forward<F>(fun),
std::forward<Xs>(xs)...);
}
};
}
辣眼睛。有没有人类能看懂的?std::views::transform
using std::views::transform;
auto fgh = transform(h) | transform(g) | transform(f);
// Calculate f( g( h(x) ) )
auto fgh_x = ranges::single_view{42} | fgh;
//fgh_x[0]
豁然开朗了家人们
template <class... Fs>
auto composer(Fs&&... functions) {
using std::views::transform;
return (transform(functions) | ...);
}
leetcode 56题,用stl算法怎么做?std::partial_sum
sort(intervals);
auto merged = views::partial_sum(intervals, [](auto curr, auto i){
return curr.second >= i.first ? std::pair{curr.first, max(curr.second, i.second)} : i;
}) | views::adjacent_remove_if([](auto i1, auto i2){
return i1.first == i2.first;
});
for (const auto& [i,j] : merged) {
std::cout << i << " " << j << "\n";
}
很精彩的讲SWAR的文章,我还没有看完
hyperfine可以分析单测执行快慢。建议执行单测可以前面加上这个跑,每次统计测试运行时间长短,来分析代码哪里引入问题,这也是一个有趣的思路
总之测试压测之类的数据,都是有用的
代码分析慢的地方是结构体比较 opetator==慢了。这个没啥好讲的,主要在于前面发现问题的思路,提前发现问题,解决问题
老生常谈了。reserve提高局部性,改动只要一点点
std::vector<std::string> tokenize(const std::string& s) {
std::vector<std::string> result;
+ // Expect four fields or less in our input.
+ result.reserve(4);
std::string::size_type f = 0;
std::string::size_type p = s.find(':');
asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群753302367和作者对线
如果有疑问评论最好在上面链接到评论区里评论,这样方便搜索,微信公众号有点封闭/知乎吞评论