公众号
RSS https://github.com/wanghenshui/cppweeklynews/releases.atom
欢迎投稿,推荐或自荐文章/软件/资源等
总算放假了
标准委员会动态/ide/编译器信息放在这里
编译器信息最新动态推荐关注hellogcc公众号 本周更新 2023-04-26 第199期
gcc 13.1发布,c++23支持丰富了一波 https://gcc.gnu.org/gcc-13/changes.html
不过没有#embed
另外群友LH_mouse的线程库合进去了
https://github.com/gcc-mirror/gcc/commit/f036d759ecee538555fa8c6b11963e4033732463
有想要体验的可以尝试下MCF
int main() {
struct foo {
int i;
bool b;
};
const int i = 42;
const auto f = std::make_from_tuple<foo>(std::forward_as_tuple(i, true));
std::cout << f.i << ' ' << f.b << '\n'; // prints 42 1
}
没啥说的
有时候写出这种代码就很烦
xml.begin_element("port");
xml.attribute("name", name);
xml.attribute("location", loc);
xml.end_element("port"); // <-- the obvious final step
还有就是事务那种
DBTransaction trx{parameters};
trx.execute(sql1);
trx.execute(sql2);
trx.commit(); // <-- the obvious final step
其实很像lock 搞个scope_guard有点大材小用,之前也提到过,对于mutex把它和保护对象合成一个类,然后暴露个with接口,比如
struct Thing {
MutexProtected<Field> field;
};
thing->field.with([&](Field& field) {
use(field);
});
按照这种思路,上面两段代码可以改成
template <typename Callback>
void XML::with_element(std::string_view name, Callback userLogic)
{
begin_element(name);
userLogic();
end_element(name);
}
// User code:
xml.with_element("port", [&] {
xml.attribute("name", name);
xml.attribute("location", loc);
});
db_transaction(parameters, [&]{
trx.execute(sql1);
trx.execute(sql2);
};
随着lambda的引入,感觉又不清晰了是不是,但是确实写的干净一些
利用sanitizer来矫正优化,修改代码,概念有点意思
代码没开源 https://github.com/vusec/LookUB
老生常谈,string string_view一些使用问题
给你一个指针和一个范围
byte* regionStart;
size_t regionSize;
if (p >= regionStart && p < regionStart + regionSize)
这样检查范围是对的吗?
不一定,看内存分配的设计,有些老系统设计可能会有一些荣誉,比如把32拆两半,前一半表示具体块,后一半表示offset,这种场景下最末端不一定等于regionstart+regioinSize,分布方式可能没那么简单
没啥说的,这个值是标准库为你准备的常见cacheline值,信不过就自已指定
考虑一个tuple合并场景,我需要tuple转发一组不同类型的参数,如果类型相同就吃掉
第一版
// Declare the template
template <typename Tuple, typename... Types>
struct TupleSet {};
// Specialize for our case: carry our 'return value'
// in the first template argument, and all the info
// to process in the rest
template <typename Type1, typename... Types, typename... TupleArgs>
struct TupleSet<std::tuple<TupleArgs...>, Type1, Types...> {
using Type = TupleSet<
std::conditional_t<
(std::same_as<TupleArgs, Type1> || ... || false),
// If `Type1` is already in the tuple, don't add it
std::tuple<TupleArgs...>,
// Else append it to the end of the tuple
std::tuple<TupleArgs..., Type1>
>, Types...
>::Type;
};
// Terminating specialization: nothing left to process
template <typename... TupleArgs>
struct TupleSet<std::tuple<TupleArgs...>> {
using Type = std::tuple<TupleArgs...>;
};
template <typename... Types>
usign TupleSetT = typename TupleSet<std::tuple<>, Types...>;
static_assert(std::same_as<TupleSetT<int, float>, std::tuple<int, float>>);
static_assert(std::same_as<TupleSetT<int, float, int>, std::tuple<int, float>>);
//使用
template <std::totally_ordered... Types>
TupleSetT<Types...> f(Types...);
已经有点反应不过来了,这里只是解决了返回值的问题,还没实现f,但是这个实现已经有点复杂了
换种思路实现,重载 operator +
// Overload operator+
// Adding a `Type` to `std::tuple` procuces a new tuple
// with `Type` as the last argument if `Type` was not in
// tuple's arguments. The return type is the same as the
// original tuple otherwise
template <typename Type, typename... Types>
std::conditional_t<
(std::same_as<Types, Type> || ... || false),
std::tuple<Types...>, std::tuple<Types..., Type>
> operator+(std::tuple<Types...>, Type);
// Note that no definition is provided for this overload
// There's not going to be one: we only need this for type
// deduction and we don't want it to be called from the
// acutual running code.
// Use C++17 fold expressions to bypass writing a recursive template
template<typename... Types>
using TupleSetT = decltype((std::declval<std::tuple<>>() + ... + std::declval<Types>()));
可能有命名空间冲突问题,这里可以通过加个名字空间来解决
namespace detail {
template<typename... Types>
using TupleSetT = decltype((std::declval<std::tuple<>>() + ... + std::declval<Types>()));
}
using detail::TupleSetT;
或者说,不用TupleSet,最终方案长这样
namespace detail {
template <std::totally_ordered Type, std::totally_ordered... Types>
constexpr auto operator+(std::tuple<Types...> tup, Type t) {
if constexpr ((std::same_as<Types, Type> || ... || false)) {
auto& tupVal = std::get<Type>(tup);
if (tupVal < t) tupVal = t;
return tup;
} else {
return std::make_tuple(std::get<Types>(tup)..., t);
}
}
}
template <std::totally_ordered... Types>
constexpr auto f(Types... args) {
using detail::operator+; // Thankfully, available at function-scope
return (std::tuple<>{} + ... + args);
}
static_assert(f(1, 2, 2.3, 5, 'c', 1.2) == std::make_tuple(5, 2.3, 'c'));
c++23怎么写?
template <typename T, typename Func>
requires std::invocable<Func, T>
constexpr auto operator>>=(T t, Func func) {
return func(t);
}
constexpr auto f(auto... args) {
constexpr auto op = [] <typename Type> (Type arg) {
return [arg] <typename... Types> (std::tuple<Types...> tup) {
if constexpr ((std::same_as<Types, Type> || ... || false)) {
auto& tupVal = std::get<Type>(tup);
if (tupVal < arg) tupVal = arg;
return tup;
} else {
return std::make_tuple(std::get<Types>(tup)..., arg);
}
};
};
return (std::tuple<>{} >>= ... >>= op(args));
}
static_assert(f(1, 2, 2.3, 5, 'c', 1.2) == std::make_tuple(5, 2.3, 'c'));
上面的代码我一行都看不懂
[build-system] # use this to indicate the name of the project
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[tool.setuptools]
package-dir = {"" = "pylib"}
packages = ["gyp", "gyp.generator"] # looks good
# end of the file
如何高效的没有if循环,干掉#?
看代码
bool overflow = 1;
for (size_t i = 0; i < b.line_end.size(); i++) {
// We subtract b.line_end from b.hash, with overflow handling.
overflow = __builtin_usubll_overflow(b.hash[i],
b.line_end[i] + overflow,
&b.comment[i]);
b.comment[i] &=~b.hash[i]; // when there is more than one #,
//we want to remove it.
b.comment[i] |= b.line_end[i]; // we want to keep the line start bits.
}
如果有疑问评论最好在上面链接到评论区里评论,这样方便搜索,微信公众号有点封闭/知乎吞评论