在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);
...
完美!!!