layout | title |
---|---|
post |
第97期 |
公众号
RSS https://github.com/wanghenshui/cppweeklynews/releases.atom
欢迎投稿,推荐或自荐文章/软件/资源等
标准委员会动态/ide/编译器信息放在这里
一月邮件列表
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/#mailing2023-01
编译器信息最新动态推荐关注hellogcc公众号 OSDT Weekly 2023-01-18 第185期
笑死 #embed
早晚玩出花来
https://godbolt.org/z/Tj6c7jz1o
#include <string_view>
#include <array>
template <std::size_t N>
struct fixed_string final {
constexpr explicit(true) fixed_string(const auto... cs) : data{cs...} {}
constexpr explicit(false) fixed_string(const char (&str)[N + 1]) {
std::copy_n(str, N + 1, std::data(data));
}
[[nodiscard]] constexpr auto operator<=>(const fixed_string&) const =
default;
[[nodiscard]] constexpr explicit(false) operator std::string_view() const {
return {std::data(data), N};
}
[[nodiscard]] constexpr auto size() const -> std::size_t { return N; }
std::array<char, N + 1> data{};
};
template <std::size_t N>
fixed_string(const char (&str)[N]) -> fixed_string<N - 1>;
fixed_string(const auto... Cs) -> fixed_string<sizeof...(Cs)>;
template<fixed_string Name>
constexpr auto meta_contains = [] {
static constexpr char self[] = {
#embed __FILE__
};
const auto code = std::string_view(std::data(self), std::size(self));
const auto find = code.find(Name);
return find != std::string_view::npos and code[find-1] != '\"';
}();
struct foo {};
struct bar {};
auto fn() -> void;
static_assert(not meta_contains<"struct x">);
static_assert(not meta_contains<"STD::string_view">);
static_assert(meta_contains<"std::string_view">);
static_assert(meta_contains<"struct foo">);
static_assert(meta_contains<"struct bar">);
static_assert(meta_contains<"auto fn()">);
再学点range
adjacent
std::vector v = { 1, 2, 3, 4, 5, 6, 7, 8 };
for (auto const& t : v | std::views::adjacent<3>) {
std::cout << '[' << std::get<0>(t) << ','
<< std::get<1>(t) << ','
<< std::get<2>(t)
<< ']' << '\n';
}
/*
[1,2,3]
[2,3,4]
[3,4,5]
[4,5,6]
[5,6,7]
[6,7,8]
*/
//也可以这样
for (auto const& [a,b,c] : v | std::views::adjacent<3>) {
std::cout << '[' << a << ',' << b << ',' << c << ']' << '\n';
}
slide和adjacent差不多,代码贴一下
auto print(R&& r) {
std::cout << '[';
bool first = true;
for (auto const e : r) {
if(first) first = false;
else std::cout << ',';
std::cout << e;
}
std::cout << ']' << '\n';
}
std::vector v = { 1, 2, 3, 4, 5, 6, 7, 8 };
for (auto const& c : v | std::views::slide(3)) {
print(c);
}
/*
[1,2,3]
[2,3,4]
[3,4,5]
[4,5,6]
[5,6,7]
[6,7,8]
*/
chunk,分段
for (auto const& c : v | std::views::chunk(3)) {
print(c);
}
/*
[1,2,3]
[4,5,6]
[7,8]
*/
chunk_by类似chunk,能提供一个谓词判断
bool differ_by_one(int const a, int const b)
{
return std::abs(a - b) <= 1;
}
std::vector v = {1,1,2,3,2,2,1,3,4,8,7,6,7};
for (auto const& c : v | std::views::chunk_by(differ_by_one))
{
print(c);
}
/* 按照相邻差1来分段
[1,1,2,3,2,2,1]
[3,4]
[8,7,6,7]
*/
再来个例子
bool same_kind(char const a, char const b)
{
bool b1 = std::isdigit(a);
bool b2 = std::isdigit(b);
return (b1 && b2) || (!b1 && !b2);
}
std::string s {"1234abc56e789fghi"};
for (auto const& c : s | std::views::chunk_by(same_kind))
{
print(c);
}
/*
按照字母类型来分段
[1,2,3,4]
[a,b,c]
[5,6]
[e]
[7,8,9]
[f,g,h,i]
*/
#include <iostream>
class MyDistance{
public:
explicit MyDistance(double i):m(i){}
friend MyDistance operator +(const MyDistance& a, const MyDistance& b){ // (1)
return MyDistance(a.m + b.m);
}
friend MyDistance operator -(const MyDistance& a, const MyDistance& b){ // (2)
return MyDistance(a.m - b.m);
}
friend std::ostream& operator<< (std::ostream &out, const MyDistance& myDist){ // (3)
out << myDist.m << " m";
return out;
}
private:
double m;
};
int main() {
std::cout << "MyDistance(5.5) + MyDistance(5.5): " << MyDistance(5.5) + MyDistance(5.5) << '\n'; // (4)
std::cout << "MyDistance(5.5) - MyDistance(5.5): " << MyDistance(5.5) - MyDistance(5.5) << '\n'; // (5)
}
没啥说的,没有friend就找不到这几个operator函数,而且这么写也不用非得是成员函数
好像之前说过这个?反复强调,undefined behavior未定义行为不等于实现定义,有可能是历史遗留问题,也有可能就毁灭地球
逆天用法
std::vector<unsigned char> getFavicon() {
return {
#embed "favicon.ico"
};
}
这种场景embed可能退化成initializer_list,复制到栈上,然后再复制到vector,堆上,白白浪费
#embed
就老老实实当属性二进制用,这种写法也不是不行,字符串不大也可以
作者写了个提案,方便解决这种情况。具体没看,大概就是识别优化掉这玩意
看段代码
#include <array>
struct Node {
int a = 1, b = 1;
};
std::array <Node, 10'000> a;
int main() {}
问题在于array占用80k额外空间,加上Node初始化占用多余的空间,怎么样能省?初始化可以用0,省掉,本身全局变量并没有很好的办法优化掉
- The Magic Behind Optimizing Compilers: Static Program Analysis - Philipp Schubert - Meeting C++ 2022
介绍静态分析工具 https://github.com/secure-software-engineering/phasar
看不懂
代码在这里 https://github.com/sslotin/amh-code
他也是咱们之前提到过很多次的这个博客 https://en.algorithmica.org/hpc/ 的作者。
这个讲的就是这个博客的内容,如何优化binary search,简单来说是SIMD,说实话SIMD我不太懂。没怎么看,不过我觉得是值得一看的
这里的aliasing表述的是多个指针使用指向同一个对象的情况,比如滥用引用,比如自己给自己赋值,之前也提到过误用引用导致错误而引入decay_copy以及c++23的auto,本质上这种问题还是指针的歧义,导致编译器保守了,没有彻底优化
来个代码
void byRef(std::vector<double>& v, const double& coeff) {
for (auto& i : v) i *= std::sin(coeff);
}
void byVal(std::vector<double>& v, double coeff) {
for (auto& i : v) i *= std::sin(coeff);
}
注意coeff这种没有必要的const&
再比如
using namespace std;
using namespace std::literals;
template <typename Fun>
void test(string_view name, Fun F) {
char buffer[50] = "hello ";
F(buffer + 1, buffer, 6);
buffer[0] = ' ';
cout << name << " [" << buffer << "] "
<< (" hello "sv == buffer ? "Good\n" : "Bad\n");
}
void loopcpy(char* dst, const char* src, int size) {
while (size--) *dst++ = *src++;
}
int main() {
test("NOP ", [](auto...) {});
test("loopcpy", loopcpy);
test("strcpy ", [](auto dst, auto src, auto...) { strcpy(dst, src); });
test("strncpy ", strncpy);
test("memcpy ", memcpy);
test("memmove", memmove);
test("copy_n ",
[](auto dst, auto src, auto size) { copy_n(src, size, dst); });
return 0;
}
loopcpy这种明显无法区分src dst相同的副作用
在比如
using namespace std;
using namespace std::literals;
int main() {
// members();
complex<int> x{2, 2};
x *= reinterpret_cast<int*>(&x)[0]; // multiply by real part
cout << "expect (4,4) and get " << x << "\n";
// lambdas();
auto add_to_all = [](auto& v, const auto& suffix) {
for_each(begin(v), end(v), [&](auto& x) { x += suffix; });
};
vector<int> v{1, 2, 3};
add_to_all(v, v[0]);
cout << "expected [2,3,4] and got [" << v[0] << "," << v[1] << "," << v[2]
<< "]\n";
return 0;
}
自己改自己以及滥用引用
再比如
int main() {
auto minmax = [](const string& i, const string& j, string* out_min,
string* out_max) {
*out_min = min(i, j);
*out_max = max(i, j);
};
array<string, 2> arr{"22222", "11111"};
// try to sort
minmax(arr[0], arr[1], &arr[0], &arr[1]);
cout << "expect 22222 and get " << arr[1] << "\n";
auto concat = [](string& result, const auto&... args) {
((result += args), ...);
};
string x{"hello "}, y{"world "};
concat(x, y, x);
cout << "expect [hello world hello ] and get [" << x << "]\n";
return 0;
}
这种问题c就有,union都有,但c有__restrict__ c++没有。那么怎么从代码角度避免这种问题?
传值,引用用std::ref,强类型区分
- asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群753302367和作者对线
- svmegn 用eigen封装svm接口
- aedis 要进boost
- blaze / HPX Parallelization 不懂
- snitch Lightweight C++20 testing framework.
- selfie
An educational software system of a tiny self-compiling C compiler, a tiny self-executing RISC-V emulator, and a tiny self-hosting RISC-V hypervisor.
如果有疑问评论最好在上面链接到评论区里评论,这样方便搜索,微信公众号有点封闭/知乎吞评论