Releases: wanghenshui/cppweeklynews
C++ 动态新闻推送 第59期
从reddit/hackernews/lobsters/meetingcpp摘抄一些c++动态
弄了个qq频道,手机qq点击进入
欢迎投稿,推荐或自荐文章/软件/资源等,请提交 issue
资讯
标准委员会动态/ide/编译器信息放在这里
编译器信息最新动态推荐关注hellogcc公众号 本周更新2022-04-20 第146期
文章
#include <tuple>
#include <cassert>
int main() {
auto [first, ...ts] = std::tuple{1, 2 ,3};
assert(1 == first);
}
看个乐。提案中
#include <iostream>
#include <string>
#include <vector>
std::vector<std::string> createStrings() {
return {"This", "is", "a", "vector", "of", "strings"};
}
int main()
{
for (auto w: createStrings()) {
std::cout << w << " "; // this works fine
}
std::cout << std::endl;
for (auto c: createStrings()[0]) {
std::cout << c << " "; // this is UB
}
std::cout << std::endl;
}
经典bug :range for里面的变量生命周期有问题
聪明的你想到了用optional,照样不行
#include <iostream>
#include <optional>
#include <string>
#include <vector>
std::vector<std::string> createStrings() {
return {"This", "is", "a", "vector", "of", "strings"};
}
std::optional<std::vector<int>> createOptionalInts() {
return std::vector<int>{1,2,3,4,5,6};
}
int main()
{
for (auto i: createOptionalInts().value()) {
std::cout << i << " "; // UB
}
const auto v = createOptionalInts().value(); //注意,必须是值,写成const auto& 一样是UB
for (auto i: v) {
std::cout << i << " ";
}
std::cout << std::endl;
}
//0 0 27344912 0 5 6 1 2 3 4 5 6
其实range for是语法糖,上面的代码等价于
#include <iostream>
#include <optional>
#include <string>
#include <vector>
std::optional<std::vector<int>> createOptionalInts() {
return std::optional<std::vector<int>>1;
}
int main()
{
auto&& range = createOptionalInts().value();
auto position = range.begin();
auto end = range.end();
for(; position != end; ++position) {
std::cout << *(position) << " "; // UB
}
std::cout << std::endl;
}
问题就在这个range已经消失了,访问这个指针就有问题
有点看不懂了
auto timedOut = std::make_shared<bool>();
auto widgetOperation = GetWidgetAsync();
auto widgetTimeout = [](auto timedOut) -> IAsyncOperation<Widget>
{
co_await winrt::resume_after(15s);
*timedOut = true;
co_return nullptr;
}(timedOut);
auto widget = co_await winrt::when_any(widgetOperation, widgetTimeout);
widgetOperation.Cancel();
widgetTimeout.Cancel();
if (*timedOut) {
// timed out
} else {
// GetWidgetAsync() produced something (possibly nullptr)
}
auto widgetOperation = GetWidgetAsync();
auto widgetTimeout = [] -> IAsyncOperation<Widget>
{
co_await winrt::resume_after(15s);
co_return nullptr;
}();
auto widget = co_await winrt::when_any(widgetOperation, widgetTimeout);
auto timedOut = widgetTimeout.Status() == AsyncStatus::Completed;
widgetOperation.Cancel();
widgetTimeout.Cancel();
if (timedOut) {
// timed out
} else {
// GetWidgetAsync() produced something (possibly nullptr)
}
CTAD把活交给了编译器推导,但大家没咋用,还是有make_xx函数来构造对象,清晰,明确
- Multi-GPU Programming with Standard Parallel C++, Part 1
- Multi-GPU Programming with Standard Parallel C++, Part 2
nvc++ compiler
软文的感觉。介绍了一些算法可以并行,比如
// Step 1: compute the number of variables contributed by every node.
int* numValuesPtr = allocateMemory(numberOfCells);
for_each(execution::par_unseq, numValuesPtr,
numValuesPtrl + numberOfCells, [=](int& numValues)
{
int i = &numValues - numValuesPtr;
// Compute number of variables contributed by current node.
numValues = computeNumValues(i);
} );
// 2. Compute the buffer index for every node.
int* indexPtr = allocateMemory(numberOfCells);
exclusive_scan(execution::par_unseq, numValuesPtr,
numValuesPtr + numberOfCells, indexPtr, 0);
// 3. Pack the data into the buffer.
for_each(execution::par_unseq, indexPtr,
indexPtr + numberOfCells, [=](int& index)
{
int i = &index - indexPtr;
packCellData(i, index);
} );
介绍gdb启动都做了什么以及如何优化启动速度
介绍vscode更新的调试功能(谁用vscode调试啊)
视频
namespace tool {
inline namespace v1_0_0 {
struct Data {
int a;
bool b;
std::string c;
};
bool foo(const Data d);
}
}
int main() {
const tool::Data d;
return tool::foo(d);
}
看到这个用法,inline namespace在调用的时候可以省掉,但是这个inline namespace的符号可以保证唯一,这样就避免了不同版本造成的ABI break
很妙,但没人用。这属于项目管理的一部分。严格来说很难出现ABI break
开源项目需要人手
- asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群384042845和作者对线
- pika 一个nosql 存储, redis over rocksdb,非常需要人贡献代码胖友们, 感兴趣的欢迎加群294254078前来对线
新项目介绍/版本更新
- mleak 劫持malloc/free 分析内存泄漏
- boostdep-report 分析boost各个组件的依赖关系 比如asio依赖boost core之类的
- vcpkg April 2022 Release is Now Available
- poco Release 1.11.2 Available
工作招聘
互联网寒冬了胖友们
看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持!
C++ 动态新闻推送 第58期
从reddit/hackernews/lobsters/meetingcpp摘抄一些c++动态
弄了个qq频道,手机qq点击进入
欢迎投稿,推荐或自荐文章/软件/资源等,请提交 issue
你们说整个代码走读周会/项目分享 靠谱么。我感觉拉不到人
资讯
标准委员会动态/ide/编译器信息放在这里
编译器信息最新动态推荐关注hellogcc公众号 2022-04-13 第145期
文章
static_assert([]<class T>{ return std::integral<T>; }.operator()<int>());
struct f { auto foo() -> void; };
static_assert([](auto t){ return requires { t.foo(); }; }(f{}));
我觉得这玩意还是不要知道的好
看个乐,挺有意思的
一些c指针的缺陷。老生常谈了属于是
复习一下chrono,c++20有个file_clock,干嘛的
windbg调试手把手教学
测了几种算法range和标准实现的表现。range下限稳定。能用range尽量用range
template<typename T>
struct Holder
{
T value;
template<typename... Args>
Holder(Args&&... args) :
value(std::forward<Args>(args)...) {}
};
template<typename U> Holder(U&&) ->
Holder<std::remove_reference_t<U>>
省一个类型缩写 Holder(42)
而不是Holder<int>42
但是问题来了,如果T的构造抛异常就完了
标记noexcept,怎么标?
template<typename... Args>
Holder(Args&&... args)
noexcept(noexcept(T(std::forward<Args>(args)...))) :
value(std::forward<Args>(args)...) {}
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class Object { // (2)
public:
template <typename T> // (3)
Object(T&& obj): object(std::make_shared<Model<T>>(std::forward<T>(obj))){}
std::string getName() const { // (4)
return object->getName();
}
struct Concept { // (5)
virtual ~Concept() {}
virtual std::string getName() const = 0;
};
template< typename T > // (6)
struct Model : Concept {
Model(const T& t) : object(t) {}
std::string getName() const override {
return object.getName();
}
private:
T object;
};
std::shared_ptr<const Concept> object;
};
void printName(std::vector<Object> vec){ // (7)
for (auto v: vec) std::cout << v.getName() << '\n';
}
struct Bar{
std::string getName() const { // (8)
return "Bar";
}
};
struct Foo{
std::string getName() const { // (8)
return "Foo";
}
};
int main(){
std::vector<Object> vec{Object(Foo()), Object(Bar())}; // (1)
printName(vec);
std::cout << '\n';
}
学会这种封装思想.虽然不太会用到
constexpr unsigned long long operator""_KiB(unsigned long long int x) {
return 1024ULL * x;
}
constexpr unsigned long long operator""_MiB(unsigned long long int x) {
return 1024_KiB * x;
}
constexpr unsigned long long operator""_GiB(unsigned long long int x) {
return 1024_MiB * x;
}
constexpr unsigned long long operator""_TiB(unsigned long long int x) {
return 1024_GiB * x;
}
constexpr unsigned long long operator""_PiB(unsigned long long int x) {
return 1024_TiB * x;
}
就是这段代码,分享给大家,增加代码可读性
作者拿这段代码到处提MR ,比如这个xenia-project/xenia#1935
还是fix_string
template <size_t Length>
struct fixed_string {
char _chars[Length+1] = {}; // +1 for null terminator
};
template <size_t N>
fixed_string(const char (&arr)[N])
-> fixed_string<N-1>; // Drop the null terminator
template <fixed_string<6> Str>
struct foo;
foo<"Hello!"> hello;
foo<"world!"> world;
foo<"nope"> b; // FAIL!
foo的这个6非常碍眼且不合理。c++20,可以自动推导了
template <fixed_string S>
struct ctad_foo {};
ctad_foo<"Hello"> h
ctad_foo<"user"> u;
更离谱的
template <fixed_string> // [1]
struct named_type {};
template <> // [2]
struct named_type<"integer"> { using type = int; };
template <> // [2]
struct named_type<"boolean"> { using type = bool; };
template <fixed_string S> // [3]
using named_type_t = named_type<S>::type;
named_type_t<"integer"> v = 42;
named_type_t<"boolean"> b = false;
template <fixed_string Name>
concept names_a_type = requires {
// Require that `named_type_t<Name>` produces a valid type
typename named_type_t<Name>;
};
static_assert(names_a_type<"integer">);
static_assert(!names_a_type<"widget">);
template <fixed_string S>
auto do_something() {
static_assert(
names_a_type<S>,
"The given string must name a registered type!");
}
类型信息真正的存下来了。不过一时半会用不上
concept+ lambda
#include <concepts>
template <auto Constraint> struct requires_ {
template <class T> requires (Constraint.template operator()<T>()) operator T();
};
#define $requires(...) requires_<[]<class _>{ return __VA_ARGS__; }>{}
template<class T>
concept fooable = requires(T t) {
t.foo(
$requires(std::integral<_>),
$requires(std::same_as<short, _>)
);
};
struct bar { void foo(); };
static_assert(not fooable<bar>);
struct foo1 { void foo(int, short); };
static_assert(fooable<foo1>);
struct foo2 { void foo(int, auto); };
static_assert(fooable<foo2>);
视频
一个编译期的json parser。代码在这里https://github.com/lefticus/json2cpp 玩出花来了
开源项目需要人手
- asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群384042845和作者对线
- pika 一个nosql 存储, redis over rocksdb,非常需要人贡献代码胖友们, 感兴趣的欢迎加群294254078前来对线
新项目介绍/版本更新
- C++20 library for comfortable and efficient dynamic polymorphism
- seer 一个gdb前端
- perf-ninja 一个c++实验课程,推荐大家都做一做,他的书这里可以领https://book.easyperf.net/perf_book
- boost 179 一些fix。没有新库,都是fix
看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持!
C++ 动态新闻推送 第57期
从reddit/hackernews/lobsters/meetingcpp摘抄一些c++动态
弄了个qq频道,手机qq点击进入
欢迎投稿,推荐或自荐文章/软件/资源等,请提交 issue
最近非常忙,更新也有拖延,见谅。解不出bug我都想跳楼了
资讯
标准委员会动态/ide/编译器信息放在这里
编译器信息最新动态推荐关注hellogcc公众号 本周更新 第144期
安全问题报告
- Chromium "Type confusion" 的bug影响QtWebEngine,请升级到Qt 5.15.9, Qt 6.2.5 or Qt 6.3.0.
- zlib1.2.11 安全问题 CVE-2018-25032 which allows memory corruption when deflating (i.e., when compressing) if the input has many distant matches.
请使用到的尽快升级版本,qt的qCompress也受影响,如果使用,务必升级
文章
int main() {
assert(std::ranges::all_of (std::array{1, 1, 1}, [](const auto& value) { return value == 1; }));
assert(std::ranges::any_of (std::array{1, 2, 3}, [](const auto& value) { return value == 2; }));
assert(std::ranges::none_of(std::array{1, 2, 3}, [](const auto& value) { return value == 4; }));
}
没啥说的,algorithm算法的range版本
作者写了个库,很有意思
查bug要先看issue和release信息。不过tcmalloc有很多都替换成mimalloc和jemalloc了。
xmake真的挺好用的。自己构建小东西,推荐使用
赵工的这个整理挺不错的。会介绍一些系统知识
老生常谈了,bool语义不清晰,要是多个参数都是bool那可要了老命了,最好不要用
几种解决办法,用enum不同类型区分,或者写注释,多写注释
主要是使用zeal的cli工具嵌入,最近才知道zeal支持linux了。可以下载cpp的文档然后用zeal-cli来搜索,省一个搜索的功夫
介绍工厂模式怎么组织代码的。这里不展开了。
struct S
{
std::function<void()> do_something;
int v;
};
S s;
s.do_something = []() { std::cout << "hello"; };
// does not print anything
std::invoke(&S::do_something, s);
为什么不打印???我明明调用了invoke
事实上得这么用
std::invoke(&S::do_something, s)();
一旦理解了这种用法,代码就有了新的写法,面向invoke编程
// Old and busted
this->dict.find(3)->second = "meow";
// New hotness
std::invoke(
static_cast<std::map<int, std::string>::iterator
(std::map<int, std::string>::*)(int const&)>(
&std::map<int, std::string>::find),
std::invoke(&MyClass::dict, this), 3)->second = "meow";
// Beyond hot
std::invoke(
static_cast<std::string& (std::string::*)(char const*)>
(&std::string::operator=),
std::invoke(&std::pair<int const, std::string>::second,
std::invoke(
static_cast<std::pair<int const, std::string>& (
std::map<int, std::string>::iterator::*)() const noexcept>
(&std::map<int, std::string>::iterator::operator*),
std::invoke(
static_cast<std::map<int, std::string>::iterator
(std::map<int, std::string>::*)(int const&)>
(&std::map<int, std::string>::find),
std::invoke(&MyClass::dict, this), 3))), "meow");
我已经看不懂invoke啥意思了
这代码里还有赋值还有引用啥的太啰嗦,封装一下
namespace mfptr
{
template<typename Object, typename...Args>
decltype(auto) find(Object&& object, Args&&...args) {
return std::forward<Object>(object).find(std::forward<Args>(args)...);
}
template<typename Object>
decltype(auto) dereference(Object&& object) {
return *std::forward<Object>(object);
}
template<typename Object, typename Arg>
decltype(auto) assign(Object&& object, Arg&& arg) {
return std::forward<Object>(object) = arg;
}
}
std::invoke(
&mfptr::assign<std::string&, char const*>,
std::invoke(&std::pair<int const, std::string>::second,
std::invoke(
&mfptr::dereference<std::map<int, std::string>::iterator>,
std::invoke(
&mfptr::find<std::map<int, std::string>&, int>,
std::invoke(&MyClass::dict, this), 3))), "meow");
看个乐,可别学。
windows相关的api我不了解,这里贴出来感兴趣的自己看看吧
- Adventures in application compatibility: The case of the RAII type that failed to run its destructor
涉及到硬件交互,硬件直接抛异常 structured exception 导致RAII没执行成功?这里和COM相关。我没有搞懂
讲压缩动画的,不了解,这里贴出来感兴趣的自己看
一个字符可能有不同的表达方式,需要归一
"\u0065\u0301".normalize() == "\u00e9".normalize()
true
开源项目需要人手
- asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群384042845和作者对线
- pika 一个nosql 存储, redis over rocksdb,非常需要人贡献代码胖友们, 感兴趣的欢迎加群294254078前来对线
新项目介绍/版本更新
看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持!
C++ 动态新闻推送 第56期
从reddit/hackernews/lobsters/meetingcpp摘抄一些c++动态
弄了个qq频道,手机qq点击进入
欢迎投稿,推荐或自荐文章/软件/资源等,请提交 issue
最近非常忙,cppcon的视频没怎么看。更新也有拖延,见谅
资讯
标准委员会动态/ide/编译器信息放在这里
编译器信息最新动态推荐关注hellogcc公众号 本周更新 第143期
文章
一个读编译器源码的大纲,可以看看
其实是api设计理念的问题。哎。工作踩坑才会明白
Daniel Lemire博士老活,还是那个数组转字符串最快的问题,如何用avx实现
void to_string_avx512ifma(uint64_t n, char *out) {
uint64_t n_15_08 = n / 100000000;
uint64_t n_07_00 = n % 100000000;
__m512i bcstq_h = _mm512_set1_epi64(n_15_08);
__m512i bcstq_l = _mm512_set1_epi64(n_07_00);
__m512i zmmzero = _mm512_castsi128_si512(_mm_cvtsi64_si128(0x1A1A400));
__m512i zmmTen = _mm512_set1_epi64(10);
__m512i asciiZero = _mm512_set1_epi64('0');
__m512i ifma_const = _mm512_setr_epi64(0x00000000002af31dc, 0x0000000001ad7f29b,
0x0000000010c6f7a0c, 0x00000000a7c5ac472, 0x000000068db8bac72, 0x0000004189374bc6b,
0x0000028f5c28f5c29, 0x0000199999999999a);
__m512i permb_const = _mm512_castsi128_si512(_mm_set_epi8(0x78, 0x70, 0x68, 0x60, 0x58,
0x50, 0x48, 0x40, 0x38, 0x30, 0x28, 0x20, 0x18, 0x10, 0x08, 0x00));
__m512i lowbits_h = _mm512_madd52lo_epu64(zmmzero, bcstq_h, ifma_const);
__m512i lowbits_l = _mm512_madd52lo_epu64(zmmzero, bcstq_l, ifma_const);
__m512i highbits_h = _mm512_madd52hi_epu64(asciiZero, zmmTen, lowbits_h);
__m512i highbits_l = _mm512_madd52hi_epu64(asciiZero, zmmTen, lowbits_l);
__m512i perm = _mm512_permutex2var_epi8(highbits_h, permb_const, highbits_l);
__m128i digits_15_0 = _mm512_castsi512_si128(perm);
_mm_storeu_si128((__m128i *)out, digits_15_0);
}
void to_string_tree_table(uint64_t x, char *out) {
static const char table[200] = {
0x30, 0x30, 0x30, 0x31, 0x30, 0x32, 0x30, 0x33, 0x30, 0x34, 0x30, 0x35,
0x30, 0x36, 0x30, 0x37, 0x30, 0x38, 0x30, 0x39, 0x31, 0x30, 0x31, 0x31,
0x31, 0x32, 0x31, 0x33, 0x31, 0x34, 0x31, 0x35, 0x31, 0x36, 0x31, 0x37,
0x31, 0x38, 0x31, 0x39, 0x32, 0x30, 0x32, 0x31, 0x32, 0x32, 0x32, 0x33,
0x32, 0x34, 0x32, 0x35, 0x32, 0x36, 0x32, 0x37, 0x32, 0x38, 0x32, 0x39,
0x33, 0x30, 0x33, 0x31, 0x33, 0x32, 0x33, 0x33, 0x33, 0x34, 0x33, 0x35,
0x33, 0x36, 0x33, 0x37, 0x33, 0x38, 0x33, 0x39, 0x34, 0x30, 0x34, 0x31,
0x34, 0x32, 0x34, 0x33, 0x34, 0x34, 0x34, 0x35, 0x34, 0x36, 0x34, 0x37,
0x34, 0x38, 0x34, 0x39, 0x35, 0x30, 0x35, 0x31, 0x35, 0x32, 0x35, 0x33,
0x35, 0x34, 0x35, 0x35, 0x35, 0x36, 0x35, 0x37, 0x35, 0x38, 0x35, 0x39,
0x36, 0x30, 0x36, 0x31, 0x36, 0x32, 0x36, 0x33, 0x36, 0x34, 0x36, 0x35,
0x36, 0x36, 0x36, 0x37, 0x36, 0x38, 0x36, 0x39, 0x37, 0x30, 0x37, 0x31,
0x37, 0x32, 0x37, 0x33, 0x37, 0x34, 0x37, 0x35, 0x37, 0x36, 0x37, 0x37,
0x37, 0x38, 0x37, 0x39, 0x38, 0x30, 0x38, 0x31, 0x38, 0x32, 0x38, 0x33,
0x38, 0x34, 0x38, 0x35, 0x38, 0x36, 0x38, 0x37, 0x38, 0x38, 0x38, 0x39,
0x39, 0x30, 0x39, 0x31, 0x39, 0x32, 0x39, 0x33, 0x39, 0x34, 0x39, 0x35,
0x39, 0x36, 0x39, 0x37, 0x39, 0x38, 0x39, 0x39,
};
uint64_t top = x / 100000000;
uint64_t bottom = x % 100000000;
uint64_t toptop = top / 10000;
uint64_t topbottom = top % 10000;
uint64_t bottomtop = bottom / 10000;
uint64_t bottombottom = bottom % 10000;
uint64_t toptoptop = toptop / 100;
uint64_t toptopbottom = toptop % 100;
uint64_t topbottomtop = topbottom / 100;
uint64_t topbottombottom = topbottom % 100;
uint64_t bottomtoptop = bottomtop / 100;
uint64_t bottomtopbottom = bottomtop % 100;
uint64_t bottombottomtop = bottombottom / 100;
uint64_t bottombottombottom = bottombottom % 100;
//
memcpy(out, &table[2 * toptoptop], 2);
memcpy(out + 2, &table[2 * toptopbottom], 2);
memcpy(out + 4, &table[2 * topbottomtop], 2);
memcpy(out + 6, &table[2 * topbottombottom], 2);
memcpy(out + 8, &table[2 * bottomtoptop], 2);
memcpy(out + 10, &table[2 * bottomtopbottom], 2);
memcpy(out + 12, &table[2 * bottombottomtop], 2);
memcpy(out + 14, &table[2 * bottombottombottom], 2);
}
avx版本要比大表快四倍,我没有编译验证,有空可以贴googlebenchmark跑一下
用宏来反射。不多说
llvm考虑引入生命周期标记,这是整体设计文档
注意span使用,内存布局不同
别用数组存指针,用boost::ptr_vector
别用数组存指针,局部性非常差
古老技术
#include <iterator>
#include <forward_list>
#include <list>
#include <vector>
#include <iostream>
template <typename InputIterator, typename Distance>
void advance_impl(InputIterator& i, Distance n, std::input_iterator_tag) {
std::cout << "InputIterator used" << '\n';
while (n--) ++i;
}
template <typename BidirectionalIterator, typename Distance>
void advance_impl(BidirectionalIterator& i, Distance n, std::bidirectional_iterator_tag) {
std::cout << "BidirectionalIterator used" << '\n';
if (n >= 0)
while (n--) ++i;
else
while (n++) --i;
}
template <typename RandomAccessIterator, typename Distance>
void advance_impl(RandomAccessIterator& i, Distance n, std::random_access_iterator_tag) {
std::cout << "RandomAccessIterator used" << '\n';
i += n; // (5)
}
template <typename InputIterator, typename Distance> // (4)
void advance_(InputIterator& i, Distance n) {
typename std::iterator_traits<InputIterator>::iterator_category category;
advance_impl(i, n, category);
}
int main(){
std::cout << '\n';
std::vector<int> myVec{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // (1)
auto myVecIt = myVec.begin();
std::cout << "*myVecIt: " << *myVecIt << '\n';
advance_(myVecIt, 5);
std::cout << "*myVecIt: " << *myVecIt << '\n';
std::cout << '\n';
std::list<int> myList{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // (2)
auto myListIt = myList.begin();
std::cout << "*myListIt: " << *myListIt << '\n';
advance_(myListIt, 5);
std::cout << "*myListIt: " << *myListIt << '\n';
std::cout << '\n';
std::forward_list<int> myForwardList{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // (3)
auto myForwardListIt = myForwardList.begin();
std::cout << "*myForwardListIt: " << *myForwardListIt << '\n';
advance_(myForwardListIt, 5);
std::cout << "*myForwardListIt: " << *myForwardListIt << '\n';
std::cout << '\n';
}
介绍c++23强类型带来的优势
emplate<double Value> constexpr auto value = Value;
int main() {
std::cout << value<4.2>; // prints 4.2
}
以前只支持整数,现在浮点数也可以了(有啥用???????? )
实现一个能处理溢出的整型,实现一个函数好还是实现一个新类型好?想象int和std::atomic<int>
嵌入式IoT环境 string选型,std::string想用用不了,std::pmr::string想用用不了 string_view可以用
range的算法要比以前的stl算法优雅,建议多用
比如
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
const std::vector numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto even = [](int i) { return 0 == i % 2; };
std::vector<int> temp;
std::copy_if(begin(numbers), end(numbers), std::back_inserter(temp), even);
std::vector<int> temp2(begin(temp)+1, end(temp));
for (auto iter = rbegin(temp2); iter!=rend(temp2); ++iter)
std::cout << *iter << ' ';
}
range
#include <algorithm>
#include <vector>
#include <iostream>
#include <ranges> // new header!
int main() {
const std::vector numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto even = [](int i) { return 0 == i % 2; };
std::ranges::reverse_view rv{
std::ranges::drop_view {
...
C++ 动态新闻推送 第54期
从reddit/hackernews/lobsters/meetingcpp摘抄一些c++动态
弄了个qq频道,手机qq点击进入
欢迎投稿,推荐或自荐文章/软件/资源等,请提交 issue
资讯
标准委员会动态/ide/编译器信息放在这里
编译器信息最新动态推荐关注hellogcc公众号 本周更新 2022-03-16 第141期
文章
看不懂说的啥
讨论了ABI带来的兼容问题
第五版优化用上了arm的sse指令重写
不多说,列代码
join_view
using namespace std::ranges;
auto l_as_string = []<typename R>(R range){
return std::string(std::begin(range), std::end(range));
};
std::vector<std::string> words{"this", "is", "a", "demo"};
auto text = l_as_string(words | views::join);
std::cout << text << '\n';//thisisademo
新接口
auto text = l_as_string(words | views::join_with(' ')); //"this is a demo"
zip_view
std::array<int, 4> n{ 1, 2, 3, 4 };
std::vector<std::string> w{ "one","two","three" };
auto z1 = views::zip(n, w) // { (1, "one"), (2, "two"), (3, "three") }
for(auto t : z1)
std::cout << std::get<0>(t) << '-'
<< std::get<1>(t) << '\n';
- overload 167
这是个期刊,每期都会录入几篇文章,文章很长。内容标题是- What are you optimizing for? 没啥说的
- Revisiting Data-Oriented Design
- An Associative Container for Non-bash Shell Scripts
- C++20 Benefits: Consistency With Ranges
没啥值得说的
讲llvm给wasm减少体积
开发simulater遇到的问题 代码在这里
讲作者怎么发现的这个缺陷以及复现过程,做安全的朋友可以看看。简单来说就是数组边界没检查,但触发这个场景构造了挺多东西
视频
尽量用static constexpr,编译期。快。有人用压测挑战了up主,说static constexpr并不比constexpr快,并给了一个bench链接,这个视频是作者的调试过程。简单来说,那个bench场景有问题,数据小,数据局部性太高,constexpr默认是栈变量,cache友好的结果,实际上数据量一大 static constexpr明显优于constexpr
更新一波cppcon 2021
对clang感兴趣的可以看看
讲所有权的。感兴趣的可以看看
嵌入式场景编译器优化减小程序体积
体积影响分发。从二进制角度观测/评估哪里可以省掉,用bloaty查
比如strip 减少内联 (__attribute__((noinline))
)/模板实例化以及二进制工具修改
编译选项,-Os -flto -Wl,--strip-all (不要-g) -fno-unroll-loops -fno-execption -fno-rtti
以及编译器本身提供的减少体积的选项,比如thin-lto(llvm) -fmerge-all-constant -mllvm hot-cold-split
代码组织上,不要继承不要类不要lambda,不要复制,实现移出头文件,数据结构简单就好,算法用简单的,不需要考虑性能问题,够用,拷贝尽量用memcpy
还有一些邪魔外道我没有列出。后面直接贴出ppt链接,有兴趣的可以点视频看看
谁用vscode调代码啊,你用吗,我不用。
如果一个类只声明不实现,不能保证成员函数是noexpect(true)的(析构函数除外),之前咱们也聊过zero cost execption相关
这个视频讨论了noexcept的方方面面。比较深入。值得一看。
实现variant/访问需要注意一些问题。AA手把手带你写代码
介绍gdb新特性,新命令,和python更好的交互等等。没细看
VS的静态检测工具,分析分支,跟踪指针生命周期
讲哲学的,太抽象了。没看
msvc的chrono实现。如何支持date timezone等等,API走读(评论区评论非常多。难道是妹子解说就人多吗)
讲range view的。对相关概念感兴趣的可以看看
手把手教你解bug
介绍boostext.ut 这个库用用户自定义前缀 UDL来实现单测的模型,而不是用宏展开。比较优雅。之前也介绍过
讲哲学的我是真听不进去
cppp
介绍SEH的
手把手带你看汇编。这个视频好像推了好几次了。真的值得一看
开源项目需要人手
- asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群384042845和作者对线
- pika 一个nosql 存储, redis over rocksdb,非常需要人贡献代码胖友们, 感兴趣的欢迎加群294254078前来对线
新项目介绍/版本更新
看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持!
C++ 动态新闻推送 第53期
从reddit/hackernews/lobsters/meetingcpp摘抄一些c++动态
弄了个qq频道,手机qq点击进入
欢迎投稿,推荐或自荐文章/软件/资源等,请提交 issue
资讯
标准委员会动态/ide/编译器信息放在这里
编译器信息最新动态推荐关注hellogcc公众号 本周更新 2022-03-09 第140期
文章
一个async对应一个future,别共用一个future,会阻塞
using my_map = unordered_map<{
.key = type<int>, .value = type<std::string>,
.allocator = type< my_allocator< std::pair<const int, std::string > > >
}>;
注意这个用法,说实话还是挺别扭。能省几行代码
有些类型是可以拷贝但不能比较的,比如function
STL中还有哪个组件类似?
constexpr std::monostate m;
static_assert(m == m);
std::monostate按理说就是个tag类型,比较没有意义,但是这里确实可以比较,本身有value语义
再比如
constexpr std::nullopt_t n;
bool b = (n == n); // Error: does not compile!
nullopt明显没有value语义
通过把输出定向到 /dev/full
可以看到错误硬件错误,这是一个测试的好手段,可以判断如果调用了硬件接口报错是不是真的处理了错误码
$ echo "Hello World!" > /dev/full
bash: echo: write error: No space left on device
$ echo $?
1
但是c/c++是没有处理的
cat hello.c
/* Hello World in C, Ansi-style */
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
puts("Hello World!");
return EXIT_SUCCESS;
}
gcc hello.c -o hello
./hello > /dev/full
echo $?
1
strace -etrace=write ./hello > /dev/full
write(1, "Hello World!\n", 13) = -1 ENOSPC (No space left on device)
+++ exited with 0 +++
作者测试了其他语言,汇总了个表格,有些处理了,有些没处理。这里就不介绍了
用模板包装
class Car {
public:
~Car() = default;
void startEngine() {
// some implementation
}
int getTrunkSize() const {
// some implementation
}
void addFuel(double quantity) {
// some implementation
}
};
class MockCar {
public:
MOCK_METHOD(void, startEngine, (), ());
MOCK_METHOD(int, getTrunkSize, (), (const));
MOCK_METHOD(void, addFuel, (double quantity), ());
};
template <typename CarImpl>
class CarWrapper {
public:
CarWrapper(C carImpl): _carImpl(carImpl) {}
void startEngine() {
_carImpl.startEngine();
}
int getTrunkSize() const {
return _carImpl.getTrunkSize();
}
void addFuel(double quantity) {
_carImpl.addFuel();
}
private:
CarImpl _carImpl;
}
CarWrapper<MockedCar> c;
另外gmock也有新组件
TEST(CarMockTest, testStatementOrder) {
::testing::NiceMock<MockCar> c;
EXPECT_CALL(c, startEngine()).Times(1);
c.startEngine();
}
可以看googlemock/docs/CookBook.md 了解更多
经典循环展开,SWAR SIMD过程,具体的推导过程可以看原文,我这里直接贴代码了
union Pixel
{
uint8_t c[4]; // four channels: red, green, blue, alpha
uint32_t v; // full pixel value as a 32-bit integer
};
void darken(Pixel* first, Pixel* last, int darkness)
{
int lightness = 256 - darkness;
for (; first < last; ++first) {
for (int i = 0; i < 3; ++i) {
first->c[i] = (uint8_t)(first->c[i] * lightness / 256);
}
}
}
//展开
void darken(Pixel* first, Pixel* last, int darkness)
{
int lightness = 256 - darkness;
for (; first < last; ++first) {
first->c[0] = (uint8_t)(first->c[0] * lightness / 256);
first->c[1] = (uint8_t)(first->c[1] * lightness / 256);
first->c[2] = (uint8_t)(first->c[2] * lightness / 256);
}
}
//算法拆解,省掉除法, SWAR
void darken(Pixel* first, Pixel* last, int darkness)
{
int factor = darkness / 8;
for (; first < last; ++first) {
uint32_t v = first->v;
uint32_t fields = (v & 0xFF) |
((v & 0xFF00) << 2) |
((v & 0xFF0000) << 4);
fields *= factor;
fields += pack_fields(31, 31, 31);
uint32_t diff = ((fields >> 5) & 0x1F) |
((fields >> 7) & 0x1F00) |
((fields >> 9) & 0x1F0000) |
first->v = v - diff;
}
}
//SIMD改写
void darken(Pixel* first, Pixel* last, int darkness)
{
int lightness = 256 - darkness;
auto lightness128 = _mm_set_epi16(
256, lightness, lightness, lightness,
256, lightness, lightness, lightness);
void* end = last;
for (auto pixels = (__m128i*)first; pixels < end; pixels++) {
auto val = _mm_loadu_si128(pixels);
auto vlo = _mm_unpacklo_epi8(val, _mm_setzero_si128());
vlo = _mm_mullo_epi16(vlo, alpha128);
vlo = _mm_srli_epi16(vlo, 8);
auto vhi = _mm_unpackhi_epi8(val, _mm_setzero_si128());
vhi = _mm_mullo_epi16(vhi, alpha128);
vhi = _mm_srli_epi16(vhi, 8);
val = _mm_packus_epi16(vlo, vhi);
_mm_storeu_si128(pixels, val);
}
}
不太懂,windows平台的,这里标记个TODO
视频
除了放在模板参数里,还可以这样
consteval auto as_constant(auto value) { return value;}
template<typename ... Param>
consteval decltype(auto) consteval_invoke(Param && ... param) {
return std::invoke(std::forward<Param>(param)...);
}
一般来说用不上
讲mock的
开源项目需要人手
- asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群384042845和作者对线
- pika 一个nosql 存储, redis over rocksdb,非常需要人贡献代码胖友们, 感兴趣的欢迎加群294254078前来对线
新项目介绍/版本更新
看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持!
C++ 动态新闻推送 第52期
从reddit/hackernews/lobsters/meetingcpp摘抄一些c++动态
弄了个qq频道,手机qq点击进入
欢迎投稿,推荐或自荐文章/软件/资源等,请提交 issue
资讯
标准委员会动态/ide/编译器信息放在这里
编译器信息最新动态推荐关注hellogcc公众号 本周更新 2022-01-05 第139期
文章
数字转字符串 sprintf性能,非常垃圾,使用fm
t或者std::to_chars
namespace adl {
struct foo {};
void bar(foo) {}
}
int main() {
adl::foo foo;
bar(foo); // OK, ADL
(bar)(foo); // error: no ADL
}
就是名字空间内的查找
#include <utility>
int main() {
std::unreachable();
return 42; // invokes undefined behavior
}
没啥说的,类似assert(false)
int main() {
std::vector v{1, 2, 3, 4};
assert(4 == std::size(v));
std::erase_if(v, [](const auto& e) { return e % 2;} );
assert(2 == std::size(v));
assert(v[0] == 2 and v[1] == 4);
}
没啥说的
手把手教你图像过滤,看不懂
图像sample 看不懂
手把手教你gmock
几个需求,编译期打印字符串,编译期生成随机数
第一个简单,就是fixed_string+static assert
struct ct_str
{
char _data[512]{};
std::size_t _size{0};
template <std::size_t N>
constexpr ct_str(const char (&str)[N]) : _data{}, _size{N - 1}
{
for(std::size_t i = 0; i < _size; ++i)
_data[i] = str[i];
}
};
template <ct_str> struct print;
constexpr ct_str test()
{
ct_str s{"Welcome to Wordlexpr!"};
s._data[0] = 'w';
s._data[11] = 'w';
s._data[20] = '.';
return s;
}
print<test()> _{};
第二个就是用fixed_string来做生成随机数的生成器,让外部指定seed和字符串,然后编译的时候改一改就行了
语言律师新活,如果itor是T*,会有一大堆冲突问题,后面是一大堆列举。这里不提了
异常,我劝你别用
c++编译依赖和头文件的问题。属于老生常谈的讨论
google benchmark教程,几个案例
基本的阻止优化
static void i32_addition_semirandom(bm::State &state) {
int32_t a = std::rand(), b = std::rand(), c = 0;
for (auto _ : state)
bm::DoNotOptimize(c = (++a) + (++b));
}
一个简单的数学算法对比
static void f64_sin(bm::State &state) {
double argument = std::rand(), result = 0;
for (auto _ : state)
bm::DoNotOptimize(result = std::sin(argument += 1.0));
}
static void f64_sin_maclaurin(bm::State &state) {
double argument = std::rand(), result = 0;
for (auto _ : state) {
argument += 1.0;
result = argument - std::pow(argument, 3) / 6 + std::pow(argument, 5) / 120;
bm::DoNotOptimize(result);
}
}
static void f64_sin_maclaurin_powless(bm::State &state) {
double argument = std::rand(), result = 0;
for (auto _ : state) {
argument += 1.0;
result = argument - (argument * argument * argument) / 6.0 +
(argument * argument * argument * argument * argument) / 120.0;
bm::DoNotOptimize(result);
}
}
[[gnu::optimize("-ffast-math")]]
static void f64_sin_maclaurin_with_fast_math(bm::State &state) {
double argument = std::rand(), result = 0;
for (auto _ : state) {
argument += 1.0;
result = argument - (argument * argument * argument) / 6.0 +
(argument * argument * argument * argument * argument) / 120.0;
bm::DoNotOptimize(result);
}
}
注意这个attrbute用法。最后一种非常快
整数除法
static void i64_division(bm::State &state) {
int64_t a = std::rand(), b = std::rand(), c = 0;
for (auto _ : state)
bm::DoNotOptimize(c = (++a) / (++b));
}
static void i64_division_by_const(bm::State &state) {
int64_t money = 2147483647;
int64_t a = std::rand(), c;
for (auto _ : state)
bm::DoNotOptimize(c = (++a) / *std::launder(&money));
}
static void i64_division_by_constexpr(bm::State &state) {
constexpr int64_t b = 2147483647;
int64_t a = std::rand(), b;
for (auto _ : state)
bm::DoNotOptimize(c = (++a) / b);
}
constexpr非常快
硬件加速
[[gnu::target("default")]] static void u64_population_count(bm::State &state) {
auto a = static_cast<uint64_t>(std::rand());
for (auto _ : state)
bm::DoNotOptimize(__builtin_popcount(++a));
}
[[gnu::target("popcnt")]] static void u64_population_count_x86(bm::State &state) {
auto a = static_cast<uint64_t>(std::rand());
for (auto _ : state)
bm::DoNotOptimize(__builtin_popcount(++a));
}
如果硬件支持popcnt指令,有优化提升
里面有个表格概括,就不截图了
视频
还是模板 + fixed_string/array 这种场景,如果fixed_string/array是相同的,由于模板实例化相同的实例会合并,所以说这就是一种压缩效果,复用数据段。
就是static assert + type traits没啥说的
又介绍个parser generator
开源项目需要人手
- asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群384042845和作者对线
- pika 一个nosql 存储, redis over rocksdb,非常需要人贡献代码胖友们, 感兴趣的欢迎加群294254078前来对线
看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持!
C++ 动态新闻推送 第51期
从reddit/hackernews/lobsters/meetingcpp摘抄一些c++动态
弄了个qq频道,手机qq点击进入
欢迎投稿,推荐或自荐文章/软件/资源等,请提交 issue
资讯
标准委员会动态/ide/编译器信息放在这里
推荐阅读 C++ exceptions are becoming more and more problematic
异常,太坑了
编译器信息最新动态推荐关注hellogcc公众号 本周更新 2022-02-23 第138期
文章
[Linux's getrandom() Sees A 8450% Improvement With Latest Code](https://git.kernel.org/pub/scm/linux/kernel/git/crng/random.git/log/)
替换了算法,使用black而不是sha1
[Chrome V8 源码 解读系列](https://www.zhihu.com/people/v8blink/posts)
这个人写了很多文章。对浏览器感兴趣的/业界人士可以关注一波。我不太懂就不多说了
[My favorite C++20 feature](https://schneide.blog/2022/02/21/my-favorite-c20-feature/)
这玩意, 确实挺方便
auto request = http_request{
.method = http_method::get,
.uri = "localhost:7634",
.headers = { { .name = "Authorization", .value = "Bearer TOKEN" } },
};
[c++反射深入浅出 - 1. ponder 反射实现分析总篇](https://zhuanlan.zhihu.com/p/471396674)
[c++反射深入浅出 - 2. property 实现分析](https://zhuanlan.zhihu.com/p/472265782)
解析ponder这个库。对于想学习反射的值得一看
[A Good Way to Handle Errors Is To Prevent Them from Happening in the First Place](https://www.fluentcpp.com/2022/02/25/a-good-way-to-handle-errors-is-to-prevent-them-from-happening-in-the-first-place/)
尽可能把错误处理掉或者用optional /expect / outcame包装处理掉
[Returning values and errors](https://rachelbythebay.com/w/2022/02/20/return/)
string* UserIP(); //1
string UserIP(string* errmsg); //2
bool GetUserIP(string* ip); //3
bool GetUserIP(string* ip, string* errmsg); //4
Result UserIP(); //5
ResultString UserIP(); //6
string UserIP(); //7
大家觉得哪个接口好?
1肯定不行,2 3 4都需要传进个string处理,比较脏, 5是不是太复杂了,6是简单版本,但是会不会又有ResultDouble之类的东西?7简单,只有ip,errmsg不放进去,也许这个才是最优解?
开放题,没有答案
[Implementing the FLIP algorithm](https://www.jeremyong.com/color%20theory/2022/02/19/implementing-the-flip-algorithm/)
图形学的东西,不太懂,这里标记TODO
[Ways to Refactor Toggle/Boolean Parameters in C++](https://www.cppstories.com/2017/03/on-toggle-parameters/)
DoImportantStuff(true, false, true, false);
我们都知道这种参数会有莫名其妙的问题,丢失值的信息,一个两个倒还好,多了难免眼花,怎么重构,封装成enum
enum class UseCacheFlag { False, True };
enum class DeferredFlag { False, True };
enum class OptimizeFlag { False, True };
enum class FinalRenderFlag { False, True };
// and call like:
RenderGlyphs(glyphs,
UseCacheFlag::True,
DeferredFlag::False,
OptimizeFlag::True,
FinalRenderFlag::False);
使用bit flag
#include <type_traits>
struct Glyphs { };
enum class RenderGlyphsFlags
{
useCache = 1,
deferred = 2,
optimize = 4,
finalRender = 8,
};
// simplification...
RenderGlyphsFlags operator | (RenderGlyphsFlags a, RenderGlyphsFlags b) {
using T = std::underlying_type_t ;
return static_cast(static_cast(a) | static_cast(b));
// todo: missing check if the new value is in range...
}
constexpr bool IsSet(RenderGlyphsFlags val, RenderGlyphsFlags check) {
using T = std::underlying_type_t ;
return static_cast(val) & static_cast(check);
// todo: missing additional checks...
}
void RenderGlyphs(Glyphs &glyphs, RenderGlyphsFlags flags)
{
if (IsSet(flags, RenderGlyphsFlags::useCache)) { }
else { }
if (IsSet(flags, RenderGlyphsFlags::deferred)) { }
else { }
// ...
}
int main() {
Glyphs glyphs;
RenderGlyphs(glyphs, RenderGlyphsFlags::useCache | RenderGlyphsFlags::optimize);
}
结构体
struct RenderGlyphsParam
{
bool useCache;
bool deferred;
bool optimize;
bool finalRender;
};
void RenderGlyphs(Glyphs &glyphs, const RenderGlyphsParam &renderParam);
// the call:
RenderGlyphs(glyphs,
{/useCache/true,
/deferred/false,
/optimize/true,
/finalRender/false});
c++20我们有了字段构造,字段信息终于有了
struct RenderGlyphsParam
{
bool useCache;
bool deferred;
bool optimize;
bool finalRender;
};
void RenderGlyphs(Glyphs &glyphs, const RenderGlyphsParam &renderParam);
// the call:
RenderGlyphs(glyphs,
{.useCache = true,
.deferred = false,
.optimize = true,
.finalRender = false});
这个更完美一些
[Supervising in C++: how to make your programs reliable](https://basiliscos.github.io/blog/2022/02/20/supervising-in-c-how-to-make-your-programs-reliable/)[](https://github.com/wanghenshui/cppweeklynews/blob/dev/posts/051.md#%E8%A7%86%E9%A2%91)
介绍c++一些Supervise管理策略以及actor框架使用,比较少用。基本上都是糊一个taskflow模型,不用什么let it crash。这种东西放在背后的管理系统来做。不在业务进程里做
视频
C++ Weekly - Ep 312 - Stop Using constexpr (And Use This Instead!)
constexpr修饰函数,没问题
constexpr修饰值,这个值未必是编译期计算(用const可以),取决于编译器,且 constexpr修饰的值肯定在堆栈,所以要注意作用域问题
[Keynote: C++'s Superpower - Matt Godbolt - CPPP 2021](https://www.youtube.com/watch?v=0_UttFDnV3k)
介绍周边生态
[Introduction to memory exploitation - Patricia Aas - Meeting C++ 2021](https://www.youtube.com/watch?v=s18lHhN-NXc)
讲fuzzer的工作原理
[Design of a C++ reflection API - Matúš Chochlík - Meeting C++ online](https://www.youtube.com/watch?v=BP0gsVy502w)
介绍他写的一个反射库
[The Basics of Profiling - Mathieu Ropert - CppCon 2021](https://www.youtube.com/watch?v=dToaepIXW4s)
没啥意思。讲window profile的
[Design and Implementation of Highly Scalable Quantifiable Data Structures in C++ - CppCon 2021](https://www.youtube.com/watch?v=ECWsLj0pgbI&list=PLHTh1InhhwT6vjwMy3RG5Tnahw0G9qIx6&index=74)[](https://github.com/wanghenshui/cppweeklynews/blob/dev/posts/051.md#%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E9%9C%80%E8%A6%81%E4%BA%BA%E6%89%8B)
这讲的是个啥啊?论文在Parallel Computing Technologies这本书里,谁能搞个电子版,原版太贵了。愣是没听明白。这里标记TODO,有机会再看吧
开源项目需要人手
[asteria](https://github.com/lhmouse/asteria) 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群384042845和作者对线
[pika](https://github.com/OpenAtomFoundation/pika)[](https://github.com/wanghenshui/cppweeklynews/blob/dev/posts/051.md#%E6%96%B0%E9%A1%B9%E7%9B%AE%E4%BB%8B%E7%BB%8D%E7%89%88%E6%9C%AC%E6%9B%B4%E6%96%B0) 一个nosql 存储, redis over rocksdb,非常需要人贡献代码胖友们, 感兴趣的欢迎加群294254078前来对线
新项目介绍/版本更新
[raw pdb](https://github.com/MolecularMatters/raw_pdb) c++17一个解析pdb的库
[ledit](https://github.com/liz3/ledit) 一个编辑器
[HFSM2 development might slow down](https://www.reddit.com/r/cpp/comments/t0od6u/hfsm2_development_might_slow_down/) 乌克兰正在打仗,作为当地人无心工作
[thread-pool](https://github.com/DeveloperPaul123/thread-pool) 又一个线程池实现
实现线程池我们真正需要的是什么?是一个干活线程还是任务的投递/管理?纯纯一个线程池轮子也就看看,用处不大
C++ 动态新闻推送 第50期
从[reddit](https://www.reddit.com/r/cpp/)/[[hackernews](https://news.ycombinator.com/)](https://news.ycombinator.com/)/[[lobsters](https://lobste.rs/)](https://lobste.rs/)/[[meetingcpp](https://www.meetingcpp.com/blog/blogroll/items/Meeting-Cpp-Blogroll-317.html)](https://www.meetingcpp.com/blog/blogroll/items/Meeting-Cpp-Blogroll-317.html)摘抄一些c++动态
[周刊项目地址](https://github.com/wanghenshui/cppweeklynews)|[[在线地址](https://wanghenshui.github.io/cppweeklynews/)](https://wanghenshui.github.io/cppweeklynews/) |[知乎专栏](https://www.zhihu.com/column/jieyaren) |[腾讯云+社区](https://cloud.tencent.com/developer/column/92884)
弄了个qq频道,[手机qq点击进入](https://qun.qq.com/qqweb/qunpro/share?_wv=3&_wwv=128&inviteCode=xzjHQ&from=246610&biz=ka)
欢迎投稿,推荐或自荐文章/软件/资源等,请[提交 issue](https://github.com/wanghenshui/cppweeklynews/issues)
资讯
标准委员会动态/ide/编译器信息放在这里
c++ summit在上海要开,三月份,两天套票接近六千,真心贵,这价格,比cppcon还贵
[Visual Studio 2022 17.1 is now available!](https://devblogs.microsoft.com/visualstudio/visual-studio-2022-17-1-is-now-available/)
[编译器信息最新动态推荐关注hellogcc公众号 本周更新 2022-02-16 第137期](https://github.com/hellogcc/osdt-weekly/blob/master/weekly-2022/2022-02-16.md)
文章
- [Did you know that C++23 added Attributes on Lambda-Expressions?](https://github.com/QuantlabFinancial/cpp_tip_of_the_week/)
constexpr auto foo = [] [[deprecated]] { };
int main() {
foo(); // operator() is deprecated
}
Lambda 可以标注
主要是利用clang的 -ftime-trace
参数
我记得gcc也有一个类似的找不到了
- [C++ Templates: How to Iterate through std::tuple: std::apply and More](https://www.cppstories.com/2022/tuple-iteration-apply/)
承接上文啊,能实现遍历打印,肯定也能实现遍历调用lambda,如何实现呢?
核心代码,之前的index_sequence搬过来,另外还需要展开变参模版
for_each_tuple和之前的printtuple类似,for_each_tuple2避免难理解,主要是依赖lambda的模版能力,也是要展开变参模版
template <typename TupleT, typename Fn, std::size_t... Is>
void for_each_tuple_impl(TupleT&& tp, Fn&& fn, std::index_sequence<Is...>) {
(fn(std::get<Is>(std::forward<TupleT>(tp))), ...);
}
template <typename TupleT, typename Fn, std::size_t TupSize = std::tuple_size_v<std::remove_cvref_t<TupleT>>>
void for_each_tuple(TupleT&& tp, Fn&& fn) {
for_each_tuple_impl(std::forward<TupleT>(tp), std::forward<Fn>(fn), std::make_index_sequence<TupSize>{});
}
template <typename TupleT, typename Fn>
void for_each_tuple2(TupleT&& tp, Fn&& fn) {
std::apply
(
[&fn]<typename ...T>(T&& ...args)
{
(fn(std::forward<T>(args)), ...);
}, std::forward<TupleT>(tp)
);
}
- [Constant references are not always your friends](https://belaycpp.com/2022/02/15/constant-references-are-not-always-your-friends/)
虽然一般来说不需要拷贝的传参数用const T&就万事大吉,但是有些场景是不行的,比如T的设计不合理
我们要考虑T设计的问题,另外小对象,不要用const T&,比如string_view span int这种 直接传value
-
[c++ execution 与 coroutine (五):异步 - 知乎 (zhihu.com)](https://zhuanlan.zhihu.com/p/441741987)
[c++ execution 与 coroutine (六):coroutine概述 - 知乎 (zhihu.com)](https://zhuanlan.zhihu.com/p/443847625)
[c++ execution 与 coroutine (七):awaiter也是sender](https://zhuanlan.zhihu.com/p/445943412)
突然得知executor进不了c++23了,哎可惜。这些概念了解一下还是可以的。抽象程度很高
- [C++ Trailing Return Types](https://www.danielsieger.com/blog/2022/01/28/cpp-trailing-return-types.html)
讨论了一下把返回值放到后面的可行性,主要原因是作者开发的库经常会遇到这个返回值类型不确定的场景,比如
template<typename A, typename B>
decltype(std::declval<A>() * std::declval<B>()) multiply(A a, B b) { return a*b; }
- [The 114 standard C++ algorithms. Introduction](https://itnext.io/the-114-standard-c-algorithms-introduction-2a75a2df4300)
标准库的算法,了解一下
考虑一种场景,成员函数修饰调用限定
void Foo::bar() & { /* ... */ }
void Foo::bar() && { /* ... */ }
void Foo::bar() const & { /* ... */ }
void Foo::bar() const && { /* ... */ }
后面这种场景是为了限定Foo在某些类型的场景下才能调用
有了deducing this就能简化。举个例子
template <typename T>
class OptionalNotDeducingThis {
// ...
constexpr T* operator->() {
return addressof(this->m_value);
}
constexpr T const*
operator->() const {
return addressof(this->m_value);
}
// ...
};
template <typename T>
class OptionalDeducingThis {
// ...
template <typename Self>
constexpr auto operator->(this Self&& self) {
return addressof(self.m_value);
}
// ...
};
this Self来决定auto,所以你要const就 T* const,你不const的就T*
- [Faster integer formatting - James Anhalt (jeaiii)’s algorithm](https://jk-jeon.github.io/posts/2022/02/jeaiii-algorithm/)
一个证书序列化成字符串的算法(itoa)比fmt库内部的算法还要快,不过fmt作者没有考虑使用这个算法。
这里简单介绍一下
最简单的写法
char* itoa_naive(std::uint32_t n, char* buffer) {
char temp[10];
char* ptr = temp + sizeof(temp) - 1;
while (n >= 10) {
*ptr = char('0' + (n % 10));
n /= 10;
--ptr;
}
*ptr = char('0' + n);
auto length = temp + sizeof(temp) - ptr;
std::memcpy(buffer, ptr, length);
return buffer + length;
}
把整数序列化到temp数组,再拷贝出去,buf是10是因为int32就那么大
显然循环除10很慢,我们可以考虑减少循环次数,然后考虑除100
然后直接把余数给算好
首先想到的优化就是查表写数,而不是计算
static constexpr char radix_100_table[] = {
'0', '0', '0', '1', '0', '2', '0', '3', '0', '4',
'0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
'1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
'1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
'2', '0', '2', '1', '2', '2', '2', '3', '2', '4',
'2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
'3', '0', '3', '1', '3', '2', '3', '3', '3', '4',
'3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
'4', '0', '4', '1', '4', '2', '4', '3', '4', '4',
'4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
'5', '0', '5', '1', '5', '2', '5', '3', '5', '4',
'5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
'6', '0', '6', '1', '6', '2', '6', '3', '6', '4',
'6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
'7', '0', '7', '1', '7', '2', '7', '3', '7', '4',
'7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
'8', '0', '8', '1', '8', '2', '8', '3', '8', '4',
'8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
'9', '0', '9', '1', '9', '2', '9', '3', '9', '4',
'9', '5', '9', '6', '9', '7', '9', '8', '9', '9'
};
char* itoa_two_digits_per_div(std::uint32_t n, char* buffer) {
char temp[8];
char* ptr = temp + sizeof(temp);
while (n >= 100) {
ptr -= 2;
std::memcpy(ptr, radix_100_table + (n % 100) * 2, 2);
n /= 100;
}
if (n >= 10) {
std::memcpy(buffer, radix_100_table + n * 2, 2);
buffer += 2;
}
else {
buffer[0] = char('0' + n);
buffer += 1;
}
auto remaining_length = temp + sizeof(temp) - ptr;
std::memcpy(buffer, ptr, remaining_length);
return buffer + remaining_length;
}
说实话这块我就看不懂了,后面更难了。这里标记个TODO,有时间研究一下
作者的一些优化经验,我看lamire老哥也关注了。写的很有噱头
- 2x faster GCD (compared to
std::gcd
)- 8-15x faster binary search (compared to
std::lower_bound
)- 7x faster segment trees
- 5x faster hash tables (compared to
std::unordered_map
)?x faster popcount- 2x faster parsing series of integers (compared to
scanf
)- ?x faster sorting (compared to
std::sort
)- 2x faster sum (compared to
std::accumulate
)- 10x faster array searching (compared to
std::find
)- 100x faster matrix multiplication (compared to “for-for-for”)
- optimal word-size integer factorization (~0.4ms per 60-bit integer)
- optimal Karatsuba Algorithm
- optimal FFT
- argmin at the speed of memory
文章很长一时半会看不完,这里先标记TODO了
- [Projections are Function Adaptors](https://brevzin.github.io/c++/2022/02/13/projections-function-adaptors/)
struct Person {
std::string first;
std::string last;
};
std::vector<Person> people = { /* ... */ };
std::vector<std::string> r_names;
std::ranges::copy_if(
people,
std::back_inserter(r_names),
[](std::string const& s) { return s[0] == 'R'; },
&Person::lastCommand Line Flags in C++
A Minimalist's Guide);
std::ranges::copy_if(
people | std::views::transform(&Person::last),
std::back_inserter(r_names),
[](std::string const& s) { return s[0] == 'R'; });
看懂这两段代码的区别了吗,第一段代码不工作,因为
视频
没啥说的
- [[SIMD algorithms]...
第49期
layout: post
title: 第49期
C++ 动态新闻推送 第49期
从reddit/hackernews/lobsters/meetingcpp1 meetingcpp2摘抄一些c++动态
弄了个qq频道,手机qq点击进入
欢迎投稿,推荐或自荐文章/软件/资源等,请提交 issue
资讯
标准委员会动态/ide/编译器信息放在这里
编译器信息最新动态推荐关注hellogcc公众号 本周更新 2022-02-02 第135期 2022-02-09 第136期
文章
#include <bit>
int main() {
constexpr auto value = std::uint16_t(0xCAFE);
std::cout << std::hex << value; // pritns cafe
std::cout << std::hex << std::byteswap(value); // prints feca
}
没啥说的
#define VARIADIC(...) __VA_OPT__(__LINE__)
VARIADIC() // `empty`
VARIADIC(a) // `line` 4
VARIADIC(a, b) // `line` 5
效果 https://godbolt.org/z/rsj9ax7xY
#define FOO(...) printf(__VA_ARGS__)
#define BAR(fmt, ...) printf(fmt, __VA_ARGS__)
FOO("this works fine");
BAR("this breaks!");
最后一行,会多出一个逗号,导致调用失败,如何吃掉这个逗号?
gcc拓展
#define BAR(fmt, ...) printf(fmt "\n", ##__VA_ARGS__)
BAR("here is a log message");
BAR("here is a log message with a param: %d", 42);
或者用这个__VA_OPT__
感觉boost.pp 里有这玩意。
另外,如何检查这个宏的编译器支持?看这里
#define PP_THIRD_ARG(a,b,c,...) c
#define VA_OPT_SUPPORTED_I(...) PP_THIRD_ARG(__VA_OPT__(,),true,false,)
#define VA_OPT_SUPPORTED VA_OPT_SUPPORTED_I(?)
PP_THIRD_ARG只要第三个参数,__VA_OPT__
支持的话展开PP_THIRD_ARG(__VA_OPT__(,),true,false,)
变成PP_THIRD_ARG(,,true,false,)
第三个就是true,不展开VA_OPT第三个就是false,挺有意思的
看个乐,杀鸡用牛刀了属于是
之前也介绍过,就是解析数字字符串的方法,如何做更快,点击回顾
这是其中之一SWAR,这里老博士重新讲一遍原理
最最简单版本
uint32_t parse_eight_digits(const unsigned char *chars) {
uint32_t x = chars[0] - '0';
for (size_t j = 1; j < 8; j++)
x = x * 10 + (chars[j] - '0');
return x;
}
这里不考虑合法性,不校验
一般来说,编译器循环展开会这样
movzx eax, byte ptr [rdi]
lea eax, [rax + 4*rax]
movzx ecx, byte ptr [rdi + 1]
lea eax, [rcx + 2*rax]
lea eax, [rax + 4*rax]
movzx ecx, byte ptr [rdi + 2]
lea eax, [rcx + 2*rax]
lea eax, [rax + 4*rax]
movzx ecx, byte ptr [rdi + 3]
lea eax, [rcx + 2*rax]
lea eax, [rax + 4*rax]
movzx ecx, byte ptr [rdi + 4]
lea eax, [rcx + 2*rax]
lea eax, [rax + 4*rax]
movzx ecx, byte ptr [rdi + 5]
lea eax, [rcx + 2*rax]
lea eax, [rax + 4*rax]
movzx ecx, byte ptr [rdi + 6]
lea eax, [rcx + 2*rax]
lea eax, [rax + 4*rax]
movzx ecx, byte ptr [rdi + 7]
lea eax, [rcx + 2*rax]
add eax, -533333328
很多都是相同的指令,整理一下
imul rax, qword ptr [rdi], 2561
movabs rcx, -1302123111085379632
add rcx, rax
shr rcx, 8
movabs rax, 71777214294589695
and rax, rcx
imul rax, rax, 6553601
shr rax, 16
movabs rcx, 281470681808895
and rcx, rax
movabs rax, 42949672960001
imul rax, rcx
shr rax, 32
我们的代码如何直接生成后面这种汇编?
SWAR SIMD within a register.其实就是让寄存器尽可能利用上,做更多的计算,从上面这个汇编就能看出来
为了达到省计算的目标,就要8个byte同时做算术
接下来就是构造了
与其一个一个的减 '\0' 不如直接整个减0x30
val = val - 0x3030303030303030;
如果你的数字串是12345678,那对应16进值就是0x0807060504030201,那
然后乘
val = (val * 10) + (val >> 8);
最终效果是这样
uint32_t parse_eight_digits_unrolled(uint64_t val) {
const uint64_t mask = 0x000000FF000000FF;
const uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32)
const uint64_t mul2 = 0x0000271000000001; // 1 + (10000ULL << 32)
val -= 0x3030303030303030;
val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8;
val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32;
return val;
}
其实别的地方也有这种技巧,比如
public static int bitCount(int i) {
// HD, Figure 5-2
i = i - ((i >>> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
i = (i + (i >>> 4)) & 0x0f0f0f0f;
i = i + (i >>> 8);
i = i + (i >>> 16);
return i & 0x3f;
}
原理 HD就是Hacker's Delight这本书的意思
其实主要构造是最难的要考虑用算数拼出来
找平均值,且不溢出
unsigned average(unsigned a, unsigned b)
{
return (a + b) / 2;
}
这个明显会溢出
如果你知道两个数的大小的话
unsigned average(unsigned low, unsigned high)
{
return low + (high - low) / 2;
}
也有一种不需要知道大小的方法
unsigned average(unsigned a, unsigned b)
{
return (a / 2) + (b / 2) + (a & b & 1);
}
当然SWAR方法更快
unsigned average(unsigned a, unsigned b)
{
return (a & b) + (a ^ b) / 2;
}
原理a + b = ((a & b) << 1) + (a ^ b) 两部分分别是头和尾
作者还讨论了不同平台下的实现方法。喜欢扣细节的可以看看
另外推荐观看CppCon 2019: Marshall Clow “std::midpoint? How Hard Could it Be?”
写了个brainfuck编译器,用上constexpr和编译器优化,不知道brainfuck的先百度下,这里直接贴代码
一个实现
enum class op
{
ptr_inc, // >
ptr_dec, // <
data_inc, // +
data_dec, // -
write, // .
read, // ,
jmp_ifz, // [, jump if zero
jmp, // ], unconditional jump
};
template <std::size_t InstructionCapacity>
struct program
{
std::size_t inst_count;
op inst[InstructionCapacity];
std::size_t inst_jmp[InstructionCapacity];
};
template <std::size_t InstructionCapacity>
void execute(const program<InstructionCapacity>& program,
unsigned char* data_ptr)
{
auto inst_ptr = std::size_t(0);
while (inst_ptr < program.inst_count)
{
switch (program.inst[inst_ptr])
{
case op::ptr_inc:
++data_ptr;
++inst_ptr;
break;
case op::ptr_dec:
--data_ptr;
++inst_ptr;
break;
case op::data_inc:
++*data_ptr;
++inst_ptr;
break;
case op::data_dec:
--*data_ptr;
++inst_ptr;
break;
case op::write:
std::putchar(*data_ptr);
++inst_ptr;
break;
case op::read:
*data_ptr = static_cast<unsigned char>(std::getchar());
++inst_ptr;
break;
case op::jmp_ifz:
if (*data_ptr == 0)
inst_ptr = program.inst_jmp[inst_ptr];
else
++inst_ptr;
break;
case op::jmp:
inst_ptr = program.inst_jmp[inst_ptr];
break;
}
}
}
template <std::size_t N>
constexpr auto parse(const char (&str)[N])
{
program<N> result{};
std::size_t jump_stack[N] = {};
std::size_t jump_stack_top = 0;
for (auto ptr = str; *ptr; ++ptr)
{
if (*ptr == '>')
result.inst[result.inst_count++] = op::ptr_inc;
else if (*ptr == '<')
result.inst[result.inst_count++] = op::ptr_dec;
else if (*ptr == '+')
result.inst[result.inst_count++] = op::data_inc;
else if (*ptr == '-')
result.inst[result.inst_count++] = op::data_dec;
else if (*ptr == '.')
result.inst[result.inst_count++] = op::write;
else if (*ptr == ',')
result.inst[result.inst_count++] = op::read;
else if (*ptr == '[')
{
jump_stack[jump_stack_top++] = result.inst_count;
result.inst[result.inst_count++] = op::jmp_ifz;
}
else if (*ptr == ']')
{
auto open = jump_stack[--jump_stack_top];
auto close = result.inst_count++;
result.inst[close] = op::jmp;
result.inst_jmp[close] = open;
result.inst_jmp[open] = close + 1;
}
}
return result;
}
如何使用?
// `x = std::getchar(); y = x + 3; std::putchar(y);`
static constexpr auto add3 = parse(",>+++<[->+<]>.");
// Use this array for our data_ptr.
unsigned char memory[1024] = {};
execute(add3, memory);
不是很难
如果想玩ji...