从reddit/hackernews/lobsters/meetingcpp摘抄一些c++动态
周刊项目地址|在线地址 |知乎专栏 | 腾讯云+社区 |
欢迎投稿,推荐或自荐文章/软件/资源等,请提交 issue
Visual Studio 2022 17.2 is now available! 支持c++20 /std:c++20
编译器信息最新动态推荐关注hellogcc公众号 本周更新 2022-05-11 第149期
复习一下c++17边角料哈, 结构化绑定支持自定义类型了,逆天
struct foo {
int i{};
std::string s{};
};
template <auto N>
const auto& get(const foo& f) {
if constexpr (N == 0) {
return f.i;
} else if constexpr (N == 1) {
return f.s;
}
}
namespace std {
template <>
struct tuple_size<::foo> : integral_constant<std::size_t, 2> {};
template <std::size_t N>
struct tuple_element<N, ::foo> {
using type = decltype(get<N>(std::declval<::foo&>()));
};
} // namespace std
int main() {
auto [i, s] = foo{.i = 42, .s = "str"};
assert(42 == i);
assert("str" == s);
}
又是一个c++协程的教程
void chop1(int* count, std::string& str) {
for (int i = 0; i < *count; ++i) {
str[i] = 0;
}
}
void chop2(int* count, std::u8string& str) {
for (int i = 0; i < *count; ++i) {
str[i] = 0;
}
}
但是,优化效果却不同,chop2能优化成memset
chop1(int*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&):
mov eax, DWORD PTR [rdi]
test eax, eax
jle .L1
xor eax, eax
.L3:
mov rdx, QWORD PTR [rsi]
mov BYTE PTR [rdx+rax], 0
add rax, 1
cmp DWORD PTR [rdi], eax
jg .L3
.L1:
ret
chop2(int*, std::__cxx11::basic_string<char8_t, std::char_traits<char8_t>, std::allocator<char8_t> >&):
mov edx, DWORD PTR [rdi]
test edx, edx
jle .L6
mov rdi, QWORD PTR [rsi]
xor esi, esi
jmp memset
.L6:
ret
为什么?指针问题。char * 由于历史原因,可以表达int,编译器默认指针收到影响,写str莫名其妙的影响到了count 所以这里的*count不会优化成不变量
当然不是说u8string是为了解决这个问题的,这个问题主要还是指针对于上下文的影响,对于简单函数,能避免指针影响的对象,就尽量用对象
压测代码在这里 https://quick-bench.com/q/k8S-i72re2G2phZLolIERVTiZJo
搜字符串boyer_moore_horspool_searcher 最快
也有avx512魔法 不过没有对比
这还有个老文章std::find() and memchr() Optimizations
不贴代码了,我也看不懂avx 512的东西,有兴趣的可以看看lamir大哥整的新活
对于一些小对象,使用move来省操作
比如
struct widget_id {
std::string value;
};
widget_id id = get_widget_id();
widget widget = find_widget_by_id(std::move(id));
但是一开始widget_id可能不是这个样子的,可能是
struct widget_id {
int value;
};
这时候就会有告警提醒,你这个move是没有任何作用的,因为int是trival 给他加上个空 析构函数就不是trival了
还有一种场景,有成员函数操作
// Remember to add power to this widget, if possible
widget_id id = get_widget_id();
if (wants_power_early()) {
add_widget_power(std::move(id));
}
...
if (is_empty(id)) {
// Nobody added power yet, let's do it now.
add_widget_power(std::move(id));
}
struct widget_id
{
int value;
bool is_empty() const { return value == 0; }
operator bool() const { return value != 0; }
};
//if (!id.is_empty())
//if (id) {
这种也导致move不了
针对上面的场景,又不想要告警,可以用
template<typename T>
constexpr decltype(auto) move_allow_trivial(T&& t) noexcept
{
return std::move(t); // NOLINT
}
没啥说的,手把手教你用协程
讲auto{} 在c++ 23中有了decay_copy的语义。说过很多次了
没啥说的,介绍graphblas api
微积分?和ML相关的?看不懂
const my::detail::SomeClass<int>& var_ref = var;
// Name of variable type.
NAMEOF_TYPE_EXPR(var_ref) -> "my::detail::SomeClass<int>"
nameof::nameof_type<decltype(var_ref)>() -> "my::detail::SomeClass<int>"
NAMEOF_FULL_TYPE_EXPR(var_ref) -> "const my::detail::SomeClass<int>&"
nameof::nameof_full_type<decltype(var_ref)>() -> "const my::detail::SomeClass<int>&"
NAMEOF_SHORT_TYPE_EXPR(var_ref) -> "SomeClass"
nameof::nameof_short_type<decltype(var_ref)>() -> "SomeClass"
using T = const my::detail::SomeClass<int>&;
// Name of type.
NAMEOF_TYPE(T) ->"my::detail::SomeClass<int>"
nameof::nameof_type<T>() -> "my::detail::SomeClass<int>"
NAMEOF_FULL_TYPE(T) -> "const my::detail::SomeClass<int>&"
nameof::nameof_full_type<T>() -> "const my::detail::SomeClass<int>&"
NAMEOF_SHORT_TYPE(T) -> "SomeClass"
nameof::nameof_short_type<T>() -> "SomeClass"
my::detail::Base* ptr = new my::detail::Derived();
// Name of type, using rtti.
NAMEOF_TYPE_RTTI(*ptr) -> "my::detail::Derived"
NAMEOF_FULL_TYPE_RTTI(*ptr) -> "volatile const my::detail::Derived&"
NAMEOF_SHORT_TYPE_RTTI(*ptr) -> "Derived"