公众号
RSS https://github.com/wanghenshui/cppweeklynews/releases.atom
欢迎投稿,推荐或自荐文章/软件/资源等
20230203
标准委员会动态/ide/编译器信息放在这里
编译器信息最新动态推荐关注hellogcc公众号 2023-02-01 第187期
有武汉线下活动,可以关注
fishshell这个项目宣布用rust重写了。理由是c++太差了周边编译设施等等太难用了之类的
对此笔者锐评:确实
reddit社区对此锐评: Stop Comparing Rust to Old C++
我觉得有点露怯了,实话实说,构建确实不好用,演进也慢,你说meson conan能用我只能说还差点意思
而且c++开源社区开发人员也差点意思,没那个功夫,但rust就很不一样,很多人愿意拿rust练手。
只能说c++周边的演进还需要加快一些。周边文章咨询写的多一些,更通俗易懂一些,知道的人越多越好。大家多写文章多分享啊
本周还有一个事情是yandex的代码泄露,磁力链接在这个答案可以看到,https://www.zhihu.com/question/580980335/answer/2867507106
这两天看了下,cpp的项目挺有意思,但两个组件库util和mapreduce是没泄露的,比较可惜,要是都泄露了我就要创业了
不过一个成熟的引擎,数据是最重要的,没有数据,工具没啥意义。
他们的代码接口风格还是98那套Interface形式,但是都用的pragram once,没用Macro Guard,给人一种老太太用神仙水的反差感
另外有人问为啥他们数据库代码没泄露。。他们用的ydb本身就是开源的。
jetbrains出的报告,关于c++20使用,编译工具cmake使用率,代码分析使用率做了个列举,这里直接贴一下
构建工具,cmake越来越普及,虽然难用
什么?你想问包管理工具?
嘻嘻,没人用
用什么测试框架?
甚至不写测试
使用什么代码分析工具?
嘻嘻,甚至不用分析工具
完整报告可以去他们官网看。这里不列举了
其实就是链式构造啦
template<typename This>
struct ToggleBuilder {
template<typename... T>
auto& When(bool flag, auto f, T&&... params)
{
auto& actualThis = static_cast<This&>(*this);
if (flag)
{
std::invoke(f, actualThis, std::forward<T>(params)...);
}
return actualThis;
}
};
class MessageBuilder : public ToggleBuilder<MessageBuilder> {
MessageBuilder& WithPayload(std::string payload)
{
m_payload = std::move(payload);
return *this;
}
//...
};
Message CreateMessage(std::string payload, const Config& config)
{
return MessageBuilder{}
WithPayload(std::move(payload)).
When(config.someSpecialRecipeEnabled, [](MessageBuilder& builder){
return builder.WithAppender(GetSpecialAppenderParams()).
WithAppender(GetAnotherSpecialAppenderParams());
}).
// ...
.Build();
}
来个现实生活中的例子,OnnxRuntime
auto session = SessionBuilder{}.
WithLogger(MakeLoggerFrom(config)).
WithModel(config.modelPath).
WithCUDAExecutionProvider(config.cudaOptions).
WithOpenVINOExecutionProvider(config.openVinoOptions).
WithOptimizationLevel(config.optimizationLevel).
WithNumberOfIntraThreads(config.intraThreads).
//...
Build();
用上面那个设计,相当于
auto session = SessionBuilder{}.
WithLogger(MakeLoggerFrom(config)).
WithModel(config.modelPath).
When(config.useCuda, &SessionBuilder::WithCUDAExecutionProvider, config.cudaOptions).
When(config.useOpenVino, &SessionBuilder::WithOpenVINOExecutionProvider, config.openVinoOptions).
WithOptimizationLevel(config.optimizationLevel).
WithNumberOfIntraThreads(config.intraThreads).
//...
Build();
当然 rust这种代码也有很多
显然能想到
std::string output = std::to_string(address >> 24);
for (int i = 2; i >= 0; i--) {
output.append(std::to_string((address >> (i * 8)) % 256) + ".");
}
使用to_chars
std::string output(4 * 3 + 3, '\0'); // allocate just one big string
char *point = output.data();
char *point_end = output.data() + output.size();
point = std::to_chars(point, point_end, uint8_t(address >> 24)).ptr;
for (int i = 2; i >= 0; i--) {
*point++ = '.';
point = std::to_chars(point, point_end, uint8_t(address >> (i * 8))).ptr;
}
output.resize(point - output.data());
干脆查表
char *to_chars_52(char *p, unsigned char x) {
constexpr std::string_view table[256] = {
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
"100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
"110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
"120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
"130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
"140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
"150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
"160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
"170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
"180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
"190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
"200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
"210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
"220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
"230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
"240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
"250", "251", "252", "253", "254", "255",
};
std::string_view sv = table[x];
std::memcpy(p, sv.data(), sv.size());
return p + sv.size();
}
// credit: Peter Dimov
std::string ipv52(const uint64_t address) noexcept {
std::string output(4 * 3 + 3, '\0');
char *p = output.data();
p = to_chars_52(p, uint8_t(address >> 24));
*p++ = '.';
p = to_chars_52(p, uint8_t(address >> 16));
*p++ = '.';
p = to_chars_52(p, uint8_t(address >> 8));
*p++ = '.';
p = to_chars_52(p, uint8_t(address >> 0));
output.resize(p - output.data());
return output;
}
代码在这里
https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/blob/master/2023/02/01/str.cpp
CPU角度省内存技巧,使用上这些技巧,你的代码搞不好变慢,各种加fence。说实话,没看懂意图
介绍UBSan的方方面面使用
老文,但挺有意思。直接贴代码了。原理去原文看吧
// should be much more precise with large b
inline double fastPrecisePow(double a, double b) {
// calculate approximation with fraction of the exponent
int e = (int) b;
union {
double d;
int x[2];
} u = { a };
u.x[1] = (int)((b - e) * (u.x[1] - 1072632447) + 1072632447);
u.x[0] = 0;
// exponentiation by squaring with the exponent's integer part
// double r = u.d makes everything much slower, not sure why
double r = 1.0;
while (e) {
if (e & 1) {
r *= a;
}
a *= a;
e >>= 1;
}
return r * u.d;
}
#include <iostream>
int main() {
for (auto x : {"hello", "coding", "world"})
std::cout << x << ", ";
}
等价于
#include <iostream>
int main()
{
{
const char *const __list21[3]{"hello", "coding", "world"};
std::initializer_list<const char *> && __range1
= std::initializer_list<const char *>{__list21, 3};
const char *const * __begin1 = __range1.begin();
const char *const * __end1 = __range1.end();
for(; __begin1 != __end1; ++__begin1) {
const char * x = *__begin1;
std::operator<<(std::operator<<(std::cout, x), ", ");
}
}
return 0;
}
std::initializer_list不能细想,越想越复杂
演示代码。说实话没怎么看懂
介绍 std::regular
的
看代码就懂了
template<class T>
concept movable = is_object_v<T> && move_constructible<T> &&
assignable_from<T&, T> && swappable<T>;
template<class T>
concept copyable = copy_constructible<T> && movable<T> && assignable_from<T&, const T&>;
template<class T>
concept semiregular = copyable<T> && default_constructible<T>;
template<class T>
concept regular = semiregular<T> && equality_comparable<T>;
满足复制交换构造赋值构造复制构造默认构造的同时支持比较
师父别念了
看代码
struct foo {
int a{};
int b{};
};
struct bar {
const int x{};
int y{};
};
struct baz : bar { };
struct other {
int a{};
char b[4]{};
};
static_assert(not std::is_layout_compatible_v<void, int>);
static_assert(not std::is_layout_compatible_v<const int*, const int&>);
static_assert(std::is_layout_compatible_v<const int, int const volatile>);
static_assert(std::is_layout_compatible_v<foo, bar>);
static_assert(std::is_layout_compatible_v<foo, baz>);
static_assert(std::is_layout_compatible_v<bar, baz>);
static_assert(not std::is_layout_compatible_v<bar, other>);
static_assert(not std::is_layout_compatible_v<bar, void>);
libcurl gumbo使用教学
关于MLIR的资料不多,这个小伙可以关注关注,大家感兴趣的可以看看
测了一下成员函数影响二进制大小,结论就是虚函数影响大,最好没成员函数。我感觉这个结论很直观,不用测也能猜到
Raymong Chen分区
最近都是winrt和协程的, 我不懂winrt,没啥说的
main
Possible?觉得main过于繁琐, 参数不好用,难以理解,给了个解决例子
#include <array>
#include <span>
#include <string_view>
constexpr std::span<std::string_view> start(int argc, char** argv) {
static std::array<std::string_view, 255> argvElements = []() -> std::array<std::string_view, 255> {
std::array<std::string_view, 255> argvElements;
for (std::size_t i = 0; i < argc; ++i) {
argvElements[i] = argv[i];
}
return argvElements;
}();
return argvElements;
}
int better_main(std::span<std::string_view> args);
int main(int argc, const char *argv[]) {
return start(argc, argc, better_main);
}
更多讨论,看这里 https://github.com/lefticus/cpp_weekly/issues/209
我怎么感觉加了这一坨更难理解了?我觉得还是不要浪费时间放在这玩意上了。
有没有需要拖地的,我会
如果有疑问评论最好在上面链接到评论区里评论,这样方便搜索,微信公众号有点封闭/知乎吞评论