c++可变模板函数的非递归化实现

在C++primer p618中介绍了递归实现的版本,主要的形式:


template<typname ARGS>
void print(const T&t,const ARGS&... rest)
{
    print(t);
    print(t,rest...);
}

template<typename T>
void print(const T& t)
{
}

这样的写法又长又臭,有没有更简便的方法呢?
比如我想用openssh的sha进行哈希,其主要过程是

SHA256CTx ctx;
CTXINIT(&ctx);

CTXUPDATE(&ctx,(const void*)data,bytesize);
...

CTXFINLIZE(&result,&ctx);

假如我有多个类型要一起进行哈希的数据,比如int,long,vector,string。如何优雅的写出模板函数呢:(假定已看过effective modern c++里的标签分派 p176)

auto result=computeHash(int,long,vector,string...);

可以利用逗号表达式与initializer_list。
C/C++语言中的逗号表达式:a=(b+c,d),其结果是a=d。依次求值,并取最后一个表达式的结果为最终值。
initializer_list:要求内容在编译期就已知,选这个我感觉是有点无奈,C++应该有更优雅的方式来实现非递归模式的。

下面上代码:

#include <bits/stdc++.h>
#include <openssl/sha.h>

using namespace std;

using HashType = array<uint8_t, SHA256_DIGEST_LENGTH>;

template <typename... ARGS>
HashType computeHash(const ARGS &...args)
{
    SHA256_CTX ctx;
    SHA256_Init(&ctx);
    std::initializer_list<int>{(internalCompute(&ctx, args, std::is_arithmetic<std::decay_t<ARGS>>()), 0)...};
    HashType result;
    SHA256_Final(result.data(), &ctx);
    return result;
}

template <typename T>
void internalCompute(SHA256_CTX *ctx, const T &data, std::true_type)
{
    const void *underlying = static_cast<const void *>(&data);
    SHA256_Update(ctx, underlying, sizeof(T));
}

template <typename T>
void internalCompute(SHA256_CTX *ctx, const T &container, std::false_type)
{
    using DataType = typename T::value_type;
    const void *underlying = static_cast<const void *>(container.data());
    size_t size = container.size() * sizeof(DataType);
    SHA256_Update(ctx, underlying, size);
}


int main(int argc, char **argv)
{
    std::string test1 = "123456";
    uint8_t a = 1;
    uint64_t b = 2;
    auto hash = computeHash(test1, a, b);
}

可以注意到

std::initializer_list<int>{(internalCompute(&ctx, args, std::is_arithmetic<std::decay_t<ARGS>>()), 0)...};

这个句子才是最为关键的,对每个模板参数依次compute,并依照是否是容器还是数值进行标签分派。因为扩展" ... "在括号外,所以也可以看成:

compute(&ctx,arg1,ARG1);
compute(&ctx,arg2,ARG2);
...

完美!!!

原文地址:https://www.cnblogs.com/manch1n/p/15484791.html