从另一个元组中对象的成员函数返回的值构造一个元组
Constructing a tuple from values returned by member functions of objects inside another tuple
(这可能是 XY Problem,所以我在实际问题之前提供了一些背景信息。)
背景
我目前有一个计算不同哈希类型(CRC32、MD5、SHA1 等)的函数(不是模板)。数据来自提供者,它只能提供指向数据块的指针时间。该函数迭代地计算数据块的哈希值。
前进到下一个chunk是一个非常耗时的操作(涉及解压),只能往前走。此外,架构必须保持零拷贝。因此,在对相同数据块进行迭代时,必须立即计算所有选定的哈希值。哈希类型选择通过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。所以我决定写一个看起来更简洁的函数模板。 return 值中没有布尔开关和虚拟元组元素:
auto [crc, sha256] = computeHashes<Hash::CRC32, Hash::MD5>(data_provider);
除了最后一步我需要实际 return 结果外,我的代码大部分都能正常工作。这是从真实代码中删减的,并且只有两个哈希函数以使示例尽可能短:
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 每个结果?硬编码的 return 看起来像这样:
return std::make_tuple(res, std::get<0>(hashers).result(),
std::get<1>(hashers).result());
这当然不合适。我该怎么做?
因为 std::apply
通过 decltype(auto)
转发 returned 值,你可以用 std::apply
和 return 构造一个元组。
这可以与您的转换合并为一个调用。
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>...>{}
);
}
(这可能是 XY Problem,所以我在实际问题之前提供了一些背景信息。)
背景
我目前有一个计算不同哈希类型(CRC32、MD5、SHA1 等)的函数(不是模板)。数据来自提供者,它只能提供指向数据块的指针时间。该函数迭代地计算数据块的哈希值。
前进到下一个chunk是一个非常耗时的操作(涉及解压),只能往前走。此外,架构必须保持零拷贝。因此,在对相同数据块进行迭代时,必须立即计算所有选定的哈希值。哈希类型选择通过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。所以我决定写一个看起来更简洁的函数模板。 return 值中没有布尔开关和虚拟元组元素:
auto [crc, sha256] = computeHashes<Hash::CRC32, Hash::MD5>(data_provider);
除了最后一步我需要实际 return 结果外,我的代码大部分都能正常工作。这是从真实代码中删减的,并且只有两个哈希函数以使示例尽可能短:
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 每个结果?硬编码的 return 看起来像这样:
return std::make_tuple(res, std::get<0>(hashers).result(),
std::get<1>(hashers).result());
这当然不合适。我该怎么做?
因为 std::apply
通过 decltype(auto)
转发 returned 值,你可以用 std::apply
和 return 构造一个元组。
这可以与您的转换合并为一个调用。
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>...>{}
);
}