C++ 中文周刊 第111期

2023-05-03 09:40:13 浏览数 (2)

C 中文周刊 第111期

弄了个qq频道,手机qq点击进入

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

文章

  • Did you know that C 17 added std::forward_as_tuple and std::make_from_tuple and what’s the difference between them
代码语言:javascript复制
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
}

没啥说的

  • The obvious final step

有时候写出这种代码就很烦

代码语言:javascript复制
xml.begin_element("port");
xml.attribute("name", name);
xml.attribute("location", loc);
xml.end_element("port");  // <-- the obvious final step

还有就是事务那种

代码语言:javascript复制
DBTransaction trx{parameters};
trx.execute(sql1);
trx.execute(sql2);
trx.commit();  // <-- the obvious final step

其实很像lock 搞个scope_guard有点大材小用,之前也提到过,对于mutex把它和保护对象合成一个类,然后暴露个with接口,比如

代码语言:javascript复制
struct Thing {
    MutexProtected<Field> field;
};

thing->field.with([&](Field& field) {
    use(field);
});

按照这种思路,上面两段代码可以改成

代码语言:javascript复制
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的引入,感觉又不清晰了是不是,但是确实写的干净一些

  • Don’t Look UB: Exposing Sanitizer-Eliding Compiler Optimizations

利用sanitizer来矫正优化,修改代码,概念有点意思

代码没开源 https://github.com/vusec/LookUB

  • The View of The String

老生常谈,string string_view一些使用问题

  • How to check if a pointer is in a range of memory

给你一个指针和一个范围

代码语言:javascript复制
byte* regionStart;
size_t regionSize;

if (p >= regionStart && p < regionStart   regionSize)

这样检查范围是对的吗?

不一定,看内存分配的设计,有些老系统设计可能会有一些荣誉,比如把32拆两半,前一半表示具体块,后一半表示offset,这种场景下最末端不一定等于regionstart regioinSize,分布方式可能没那么简单

  • Why is std::hardware_destructive_interference_size a compile-time constant instead of a run-time value?

没啥说的,这个值是标准库为你准备的常见cacheline值,信不过就自已指定

  • Fold Expressions for Metaprogramming or “The Wrong Reason to Rightfully Want Extension Methods in C ”

考虑一个tuple合并场景,我需要tuple转发一组不同类型的参数,如果类型相同就吃掉

第一版

代码语言:javascript复制
// 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

代码语言:javascript复制
// 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>()));

可能有命名空间冲突问题,这里可以通过加个名字空间来解决

代码语言:javascript复制
namespace detail {
template<typename... Types>
using TupleSetT = decltype((std::declval<std::tuple<>>()   ...   std::declval<Types>()));
}
using detail::TupleSetT;

或者说,不用TupleSet,最终方案长这样

代码语言:javascript复制
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怎么写?

代码语言:javascript复制
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'));

上面的代码我一行都看不懂

  • Vectorized trimming of line comments toml文件长这样
代码语言:javascript复制
[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循环,干掉#?

看代码

代码语言:javascript复制
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.
}

开源项目需要人手

  • asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群384042845和作者对线
  • Unilang deepin的一个通用编程语言,点子有点意思,也缺人,感兴趣的可以github讨论区或者deepin论坛看一看。这里也挂着长期推荐了
  • paozhu 国人开发的web库,和drogon联系过没共建而考虑自己的需求基于asio开发。感兴趣的可以体验一下,挂在这里长期推荐了

新项目介绍/版本更新

  • BppTree一个b树实现
  • fixed-containers

0 人点赞