【问题标题】:Constructing a tuple from values returned by member functions of objects inside another tuple从另一个元组内对象的成员函数返回的值构造一个元组
【发布时间】:2019-08-03 14:45:14
【问题描述】:

(这可能是XY Problem,所以我在实际问题之前提供了一些背景信息。)

背景

我目前有一个计算不同哈希类型(CRC32、MD5、SHA1 等)的函数(不是模板)。数据来自一次只能提供指向数据块的指针的提供程序。该函数迭代地计算数据块的哈希值。

前进到下一个块是一项非常昂贵的操作(涉及解压缩),并且只能前进。此外,架构必须保持零拷贝。因此,必须在迭代相同的数据块时一次计算所有选定的哈希值。哈希类型选择是通过bool参数完成的:

std::tuple<uint32_t, QByteArray, QByteArray, QByteArray>
computeHashes(DataProvider& data, bool do_crc, bool do_md5, bool do_sha1,
              bool do_sha256);

如果其中一个标志是false,则调用者忽略相应的空元组元素。

实际问题

我对上面的 API 很不满意。所以我决定写一个看起来更干净的函数模板。返回值中没有布尔开关和虚拟元组元素:

auto [crc, sha256] = computeHashes<Hash::CRC32, Hash::MD5>(data_provider);

我得到的代码大部分都在工作,除了我需要实际返回结果的最后一步。这是从真实代码中删减的,并且只有两个哈希函数以使示例尽可能简短:

enum class Hash { CRC32, MD5 };

template <HashType> struct Hasher
{};

template<> struct Hasher<HashType::CRC32>
{
    void addData(const char* data, int len);
    uint32_t result() const;
};

template<> struct Hasher<HashType::MD5>
{
    void addData(const char* data, int len);
    QByteArray result() const;
};

template <HashType... hash_types>
auto computeHashes(DataProvider& provider)
{
    std::tuple<Hasher<hash_types>...> hashers;

    while (provider.hasMoreChunks()) {
        auto [chunk, len] = provider.nextChunk();
        std::apply([chunk, len](auto&... hasher)
                       { (..., hasher.addData(chunk, len); },
                   hashers);
    }
    return std::make_tuple( ??? );
}

我被困在最后一步:如何返回每个结果?硬编码的返回值如下所示:

return std::make_tuple(res, std::get<0>(hashers).result(),
                       std::get<1>(hashers).result());

这当然不合适。我该怎么做?

【问题讨论】:

  • 您可能会考虑研究 Hana,它有一大堆用于元组的功能实用程序。
  • 类似return std::apply([](auto&amp;&amp;... hasher){ return std::tuple(hasher.result()...); }, hashers); ?
  • @Sopel 确实有效!把它变成一个答案。

标签: c++ c++17 return-value variadic-templates stdtuple


【解决方案1】:

因为std::apply 将返回的值转发给decltype(auto),所以你可以用std::apply 构造一个元组并返回它。 这可以与您的转换合并为一个调用。

template <HashType... hash_types>
static auto computeHashes(DataProvider& provider)
{
    return std::apply(
        [&provider](auto&&... hashers) { 
            while (provider.hasMoreChunks()) 
            {
                auto [chunk, len] = provider.nextChunk();
                (..., hashers.addData(chunk, len));
            }

            return std::make_tuple(std::move(hashers.result())...);
        },
        std::tuple<Hasher<hash_types>...>{}
    );
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-13
    • 2018-04-11
    • 2012-08-15
    相关资源
    最近更新 更多