C++17 std::transform_reduce的替代实现

ygya80vv  于 2023-07-01  发布在  其他
关注(0)|答案(1)|浏览(147)

我在一个使用c20标准开发的项目上工作,但我需要在一个旧的嵌入式linux设备上构建它,其中最高的可用标准是c17(gcc 8.3.0)。分析代码库,我意识到唯一禁止代码编译的c++20特性要求是std::transform_reduce的湖,它会得到以下错误:

error: ‘transform_reduce’ is not a member of ‘std’

代码的引用部分是:

auto addresses_string = std::transform_reduce(
    localAddresses.begin(), localAddresses.end(), std::string(""),
    [](const std::string& a, const std::string& b) {
      return a + " | " + b;
    },
    [](InetAddress addr) { return addr.str(); });

但是当我检查std文档时,似乎c17已经实现了大部分的std::transform_reduce签名。此项目是一个基于CMake的项目,它包含设置为使用c17标准的以下变量

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

我想知道我是否做错了什么,或者是否有一个可能的替代实现可用于c++17中丢失的函数,或者我如何在不改变程序高级行为的情况下实现相同的逻辑。

xpcnnkqh

xpcnnkqh1#

不牺牲表现力的解决方案包括将transform_reduce编写为简单的std::accumulate。为此,您需要一个实用程序来生成map_reduce运算符:

template <class M, class R>
auto map_reduce(M&& map, R&& reduce) {
    return [m = std::forward<M>(map), 
            r = std::forward<R>(reduce)](auto& acc, auto&& val) mutable {
        return r(acc, m(std::forward<decltype(val)>(val)));
    };
}

你的调用可以用C++17写成:

std::accumulate(
    localAddresses.begin(), localAddresses.end(), std::string(""),
    map_reduce(
        [](InetAddress addr) { return addr.str(); },     // transformer    
        [](const std::string& a, const std::string& b) { // accumulator
            return a + " | " + b;
        });

Demo(使用转换为字符串的数字而不是地址)。
如果你知道如何表达你的累加器,减少(std::accumulate/std::reduce)几乎可以做任何事情。要了解兔子洞有多深,请查看此演示文稿。
一个更普通的解决方案是“借用”transform_reduce的实现(比如从这里),并使其仅在以下情况下才在头文件中可用:

#if __cplusplus < 202002L // Using standard older than C++20
  // implementation goes here
#endif

当然,在一个跨平台的项目中,你必须考虑语言标准和编译器的组合,因为一些库的功能是按照标准顺序实现的。

相关问题