C++ 中文周刊 第111期

周刊项目地址

公众号

RSS https://github.com/wanghenshui/cppweeklynews/releases.atom

欢迎投稿,推荐或自荐文章/软件/资源等

提交 issue

总算放假了


资讯

标准委员会动态/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.
}

开源项目需要人手

新项目介绍/版本更新

本文永久链接

如果有疑问评论最好在上面链接到评论区里评论,这样方便搜索,微信公众号有点封闭/知乎吞评论

看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持! 觉得写的不错那就给点吧, 在线乞讨 微信转账