layout | title |
---|---|
post |
第50期 |
从reddit/hackernews/lobsters/meetingcpp摘抄一些c++动态
欢迎投稿,推荐或自荐文章/软件/资源等,请提交 issue
标准委员会动态/ide/编译器信息放在这里
c++ summit在上海要开,三月份,两天套票接近六千,真心贵,这价格,比cppcon还贵
Visual Studio 2022 17.1 is now available!
编译器信息最新动态推荐关注hellogcc公众号 本周更新 2022-02-16 第137期
constexpr auto foo = [] [[deprecated]] { };
int main() {
foo(); // operator() is deprecated
}
Lambda 可以标注
主要是利用clang的 -ftime-trace
参数
我记得gcc也有一个类似的找不到了
承接上文啊,能实现遍历打印,肯定也能实现遍历调用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)
);
}
虽然一般来说不需要拷贝的传参数用const T&就万事大吉,但是有些场景是不行的,比如T的设计不合理
我们要考虑T设计的问题,另外小对象,不要用const T&,比如string_view span int这种 直接传value
-
c++ execution 与 coroutine (五):异步 - 知乎 (zhihu.com)
突然得知executor进不了c++23了,哎可惜。这些概念了解一下还是可以的。抽象程度很高
讨论了一下把返回值放到后面的可行性,主要原因是作者开发的库经常会遇到这个返回值类型不确定的场景,比如
template<typename A, typename B>
decltype(std::declval<A>() * std::declval<B>()) multiply(A a, B b) { return a*b; }
标准库的算法,了解一下
考虑一种场景,成员函数修饰调用限定
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*
一个证书序列化成字符串的算法(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了
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::last);
std::ranges::copy_if(
people | std::views::transform(&Person::last),
std::back_inserter(r_names),
[](std::string const& s) { return s[0] == 'R'; });
看懂这两段代码的区别了吗,第一段代码不工作,因为
没啥说的
有时间可以看一下。simd感觉早晚得了解,躲不开
这里标记一个TODO,后面看了总结一下
- asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群753302367和作者对线