公众号
RSS https://github.com/wanghenshui/cppweeklynews/releases.atom
欢迎投稿,推荐或自荐文章/软件/资源等
标准委员会动态/ide/编译器信息放在这里
编译器信息最新动态推荐关注hellogcc公众号 本周更新 2023-05-24 第203期
五月邮件列表 https://isocpp.org/blog/2023/05/2023-05-mailing-available
template <class...> struct whats_my_type;
int main() { whats_my_type<std::make_index_sequence<7>>{}; }
// error: implicit instantiation of undefined template
// ‘whats_my_type<std::integer_sequence<unsigned long, 0, 1, 2, 3, 4, 5, 6>’<source>:8:3: error: implicit instantiation of undefined template ‘whats_my_type<std::integer_sequence<unsigned long, 0, 1, 2, 3, 4, 5, 6>’
这玩意还是挺有用的
如果key已经是排好序的,插入可以O1
// Amortized linear overall insertion time if the range is sorted by key
// or reverse sorted by key. Performance degrades toward O(n log n) the more
// the list is not sorted.
template<typename C, typename Iterator>
auto try_emplace_mostly_sorted(C&& c, Iterator first, Iterator last)
-> decltype(c.end())
{
auto prev = c.end();
for (; first != last; ++first) {
prev = c.try_emplace(prev, first->key, first->value);
}
return prev;
}
llvm实现在这里,感兴趣的可以看看
https://github.com/llvm/llvm-project/blob/387c49f693c82bdf8b9b0f1ef48a92f51bb781b4/libcxx/include/__tree#L2027
新的编译器对constexpr放松要求,比如
#if __cpp_lib_optional >= 202106
constexpr
#endif
char xdigit(int n) {
static constexpr char digits[] = "0123456789abcdef";
return digits[n];
}
另外就是
optional
unique_ptr
variant
,
<cmath>
<cstdlib>
std::to_chars()
std::from_chars()
以及constexpr new/delete
都支持constexpr
就是让枚举支持位运算组合,就像传统c的用法那样,但是枚举类是强类型,转换很不方便,怎么办?实现operator |
比如
enum class ERenderPass : uint8_t {
None = 0,
Geometry = 1 << 0,
Lighting = 1 << 1,
Particles = 1 << 2,
};
inline constexpr ERenderPass operator|(ERenderPass Lhs, ERenderPass Rhs) {
return static_cast<ERenderPass>(
static_cast<std::underlying_type_t<ERenderPass>>(Lhs) |
static_cast<std::underlying_type_t<ERenderPass>>(Rhs));
}
ERenderPass Primary = ERenderPass::Geometry | ERenderPass::Lighting;
用宏更干净
#include <type_traits>
// Define bitwise operators for an enum class, allowing usage as bitmasks.
#define DEFINE_ENUM_CLASS_BITWISE_OPERATORS(Enum) \
inline constexpr Enum operator|(Enum Lhs, Enum Rhs) { \
return static_cast<Enum>( \
static_cast<std::underlying_type_t<Enum>>(Lhs) | \
static_cast<std::underlying_type_t<Enum>>(Rhs)); \
} \
inline constexpr Enum operator&(Enum Lhs, Enum Rhs) { \
return static_cast<Enum>( \
static_cast<std::underlying_type_t<Enum>>(Lhs) & \
static_cast<std::underlying_type_t<Enum>>(Rhs)); \
} \
inline constexpr Enum operator^(Enum Lhs, Enum Rhs) { \
return static_cast<Enum>( \
static_cast<std::underlying_type_t<Enum>>(Lhs) ^ \
static_cast<std::underlying_type_t<Enum>>(Rhs)); \
} \
inline constexpr Enum operator~(Enum E) { \
return static_cast<Enum>( \
~static_cast<std::underlying_type_t<Enum>>(E)); \
} \
inline Enum& operator|=(Enum& Lhs, Enum Rhs) { \
return Lhs = static_cast<Enum>( \
static_cast<std::underlying_type_t<Enum>>(Lhs) | \
static_cast<std::underlying_type_t<Enum>>(Lhs)); \
} \
inline Enum& operator&=(Enum& Lhs, Enum Rhs) { \
return Lhs = static_cast<Enum>( \
static_cast<std::underlying_type_t<Enum>>(Lhs) & \
static_cast<std::underlying_type_t<Enum>>(Lhs)); \
} \
inline Enum& operator^=(Enum& Lhs, Enum Rhs) { \
return Lhs = static_cast<Enum>( \
static_cast<std::underlying_type_t<Enum>>(Lhs) ^ \
static_cast<std::underlying_type_t<Enum>>(Lhs)); \
}
enum class ERenderPass : uint8_t {
None = 0,
Geometry = 1 << 0,
Lighting = 1 << 1,
Particles = 1 << 2,
All = Geometry | Lighting | Particles,
};
DEFINE_ENUM_CLASS_BITWISE_OPERATORS(ERenderPass);
或者用enable_if 不用宏,有洁癖
#include <type_traits>
// Define a templatized struct to contain a bool constexpr that controls
// when the operators get generated.
template <typename E>
struct FEnableBitmaskOperators {
static constexpr bool enable = false;
};
// This operator is only defined in the candidate set for a given type if the
// std::enable_if_t below evaluates to true, otherwise it is dropped.
template <typename E>
typename std::enable_if_t<FEnableBitmaskOperators<E>::enable, E> operator|(
E Lhs, E Rhs) {
return static_cast<E>(static_cast<std::underlying_type_t<E>>(Lhs) |
static_cast<std::underlying_type_t<E>>(Rhs));
}
// Rest of the operators...
With the following usage:
enum class ERenderPass : uint8_t {
...
};
// Specialize the struct to enable the operators for our enum.
template <>
struct FEnableBitmaskOperators<ERenderPass> {
static constexpr bool enable = true;
};
// Works!
ERenderPass Primary = ERenderPass::Geometry | ERenderPass::Lighting;
实际上valkan cpp就是这么干的
template <typename BitType, typename std::enable_if<FlagTraits<BitType>::isBitmask, bool>::type = true>
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR Flags<BitType> operator|( BitType lhs, BitType rhs ) VULKAN_HPP_NOEXCEPT {
return Flags<BitType>( lhs ) | rhs;
}
各取所需,我选第二种
手把手教你如何优化哈希表的API
优化find find经常会有一个检查iter的动作,非常多余,如果直接返回Optional<Value const&>
,并且支持value_or
,就干净的多
auto find(Key const&) -> iterator;
auto find(Key const&) -> Optional<pair<Key const, Value>&>;
auto find(Key const&) -> Optional<Value&>;
auto find(Key const&) -> Value;
但是find接口太多了。作者给了个特化建议
struct return_element {
template <input_iterator I>
static auto from_value(I const& it) -> Optional<iter_reference_t<I>> {
return *it;
}
template <input_iterator I>
static auto from_end(I const&) -> Optional<iter_reference_t<I>> {
return {};
}
};
struct return_value {
template <input_iterator I>
static auto from_value(I const& it) -> Optional<decltype(it->second)> {
return it->second;
}
template <input_iterator I>
static auto from_end(I const&) -> Optional<decltype(it->second)> {
return {};
}
};
struct return_value_or_zero {
template <input_iterator I>
static auto from_value(I const& it) -> decltype(auto(it->second))
return it->second;
}
template <input_iterator I>
static auto from_end(I const&) -> decltype(auto(it->second))
return {};
}
};
auto a = map.find(key); // iterator
auto b = map.find<return_element>(key); // Optional<pair<Key const, Value>&>
auto c = map.find<return_value>(key); // Optional<Value&>
auto d = map.find<return_value_or_zero>(key); // Value
优化insert
insert可能不成功,所以需要推迟value构造,惰性构造
template <class F>
struct lazy_call {
F f;
template <class T> operator T() { return f(); }
};
#define LAZY(expr) lazy_call{[&]{ return expr; }}
auto [iter, success] = map.try_emplace(key, LAZY(acquire_value()));
这个思路还是很有用的
有提案 P3288 std::elide 不知道有没有机会合入,代码还是很简单的 https://godbolt.org/z/rd5qbfE7E
windows总是有这种稀奇古怪的错误,类似的有 shouldn’t name your DLL “security.dll
问题,给这个类写CTAD推导指引
template<class... Ts>
class Foo {
public:
explicit Foo(Ts... as, Ts... bs) :
a_(static_cast<Ts&&>(as)...),
b_(static_cast<Ts&&>(bs)...) {}
private:
std::tuple<Ts...> a_;
std::tuple<Ts...> b_;
};
答案是当前还实现不了。。。不过可以实现一个make_foo https://godbolt.org/z/zTrcxnbbP
代码简单贴一下
template<class... TsTs>
struct foo_of_first_half {
template<size_t I>
using IthElement = std::tuple_element_t<I, std::tuple<TsTs...>>;
template<size_t... Is>
static auto f(std::index_sequence<Is...>)
-> Foo<IthElement<Is>...>;
static constexpr size_t N = sizeof...(TsTs) / 2;
using type = decltype(f(std::make_index_sequence<N>()));
};
template<class, class>
struct is_doubled : std::false_type {};
template<class... Ts>
struct is_doubled<Foo<Ts...>, Foo<Ts..., Ts...>> : std::true_type {};
template<class... TsTs, class FooTs = typename foo_of_first_half<TsTs...>::type>
requires is_doubled<FooTs, Foo<TsTs...>>::value
FooTs make_foo_guide(TsTs... tsts);
template<class... TsTs, class FooTs = decltype(make_foo_guide(std::declval<TsTs>()...))>
FooTs make_foo(TsTs&&... tsts) {
return FooTs(std::forward<TsTs>(tsts)...);
}
看不懂
魔改clickhouse,也算有点意思
一段问题代码
extern concurrency::task<int> get_id_async();
void test(){
try {
get_id_async().then([=](int id) {
return get_name_from_id_async(id);
}).then([=](std::string name) {
update_name(name);
});
} catch (...) {
/* deal with the exception */
}
}
问题出在哪里?get_name_from_id_async生成的task可能出现异常没捕获,不是函数,是函数生成的task本身
得改成这个
void test() {
try {
get_id_async().then([=](int id) {
return get_name_from_id_async(id);
}).then([=](std::string name) {
update_name(name);
}).then([=](concurency::task<void> precedent) {
try {
precedent.get();
} catch (...) {
/* deal with exceptions in the tasks */
}
});
} catch (...) {
/* deal with exceptions building the task chain */
}
}
说实话我不是很懂,不如co
concurrency::task<void> test() {
try {
auto id = co_await get_id_async();
auto name = co_await get_name_from_id_async(id);
update_name(name);
} catch (...) {
/* deal with exceptions */
}
}
我怎么感觉有人写过类似的?
template<class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
/// Starts the std::visit function
#define do_match std::visit(overloaded
/// The first part of a lambda statement
#define match_case(T) [&](T& var)
/// Closes the std::visit function passing in the matched value
#define match_value(value) , value)
struct IPv4 { std::string value; };
struct IPv6 { std::string value; };
int main() {
std::variant<IPv4, IPv6> variant_value = IPv4{"192.168.0.1"};
do_match {
match_case(IPv4) { std::cout << "IPv4: " << var.value << std::endl; },
match_case(IPv6) { std::cout << "IPv6: " << var.value << std::endl; },
match_case(auto) { std::cout << "Any case" << std::endl; },
} match_value(variant_value);
return 0;
}
More than a rehash Joaquín M López
介绍boost flat_map为啥牛逼,开放地址法为啥牛逼,cache友好且SIMD加速,以及hash选用各种方面。值得一看,我感觉可以把这个演讲复述一遍,确实挺牛逼的
这个讲的也是性能优化代码相关。比较常规。感兴趣可以看看。感觉翻来倒去还是那点玩意
另外还没入门的想学一下c++ 家人们 看这个 【-宵夜同学的个人空间-哔哩哔哩】 https://space.bilibili.com/1825238732
如果有疑问评论最好在上面链接到评论区里评论,这样方便搜索,微信公众号有点封闭/知乎吞评论