variadic template

turing-complete 2014-01-11 09:18:35
下面的代码有没有更简单的方法实现相同的功能:支持若干个输入参数,获取一个md5值。
现在的问题是,为了实现这个功能,要写三个函数,感觉有点多。
另,我不想用这个帖子上的解决方案。

inline void InternalMD5Update(MD5_CTX* ctx, const std::string& data) {
MD5_Update(ctx, data.data(), data.size());
}

template<typename... TArgsPack>
void InternalMD5Update(MD5_CTX* ctx, const std::string& data, const TArgsPack&... args) {
InternalMD5Update(ctx, data);
InternalMD5Update(ctx, args...);
}

template<typename... TArgsPack>
std::string GetMd5(const TArgsPack&... args) {
MD5_CTX ctx;
unsigned char md5[16];
MD5_Init(&ctx);

InternalMD5Update(&ctx, args...);

MD5_Final(md5, &ctx);

return std::string(md5, sizeof(md5));
}
...全文
244 11 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
taodm 2014-01-12
  • 打赏
  • 举报
回复
for (const std::string* data : {&args...}) {
turing-complete 2014-01-12
  • 打赏
  • 举报
回复
经过大家的提议,这是目前总结出来的一个较好的替换方案,函数个数从3个减为1。 但,还是有些差强人意,这里面有循环,而且std::initializer_list<std::string>可能还有复制。
template<typename... TArgsPack>                                                                                                                                                                
std::string GetMd5(const TArgsPack&... args) {                                                 
  MD5_CTX ctx;                                                                                 
  unsigned char md5[16];                                                                       
  MD5_Init(&ctx);                                                                              
                                                                                               
  for (const std::string& data : {args...}) {                                                  
    MD5_Update(&ctx, data.data(), data.size());                                                
  }                                                                                            
                                                                                               
  MD5_Final(md5, &ctx);                                                                        
                                                                                               
  return ConvertBytesToHexString(md5, sizeof(md5));                                            
}
ri_aje 2014-01-12
  • 打赏
  • 举报
回复
引用 9 楼 mougaidong 的回复:
经过大家的提议,这是目前总结出来的一个较好的替换方案,函数个数从3个减为1。 但,还是有些差强人意,这里面有循环,而且std::initializer_list<std::string>可能还有复制。
template<typename... TArgsPack>                                                                                                                                                                
std::string GetMd5(const TArgsPack&... args) {                                                 
  MD5_CTX ctx;                                                                                 
  unsigned char md5[16];                                                                       
  MD5_Init(&ctx);                                                                              
                                                                                               
  for (const std::string& data : {args...}) {                                                  
    MD5_Update(&ctx, data.data(), data.size());                                                
  }                                                                                            
                                                                                               
  MD5_Final(md5, &ctx);                                                                        
                                                                                               
  return ConvertBytesToHexString(md5, sizeof(md5));                                            
}
怕复制开销,可以改成这样。

    auto const f = [&](std::string const &s)
    {
        MD5_Update(&ctx,s.data(),s.size());
        return true;
    };
    for (auto const& _ : {f(ts)...}) { (void)_; } 
其实主楼是最简单的方法了,要想再写的简单漂亮只能依赖库的支持了,可惜 c++11 没有 static_for_each。 后面给的循环或者 list initialization 的方法无法保证编译期展开;而使用变参函数模板又不能保证求值顺序,都是以词骇意的感觉。
vipcxj 2014-01-11
  • 打赏
  • 举报
回复
引用 7 楼 taodm 的回复:
还没折腾结束啊 vector<string *> + initializer_list + parameter pack expansion



template<typename... TArgsPack>
std::string GetMd5(const TArgsPack&&... args) {
  std::array<std::string, sizeof...(args)> arr = {std::forward<TArgsPack>(args)...};
  MD5_CTX ctx;
  unsigned char md5[16];
  MD5_Init(&ctx);

  for (std::string& data : arr)
  {
     MD5_Update(ctx, data, data.size());
  }
 
  MD5_Final(md5, &ctx);
 
  return std::string(md5, sizeof(md5));
}

谢谢LS提醒~
taodm 2014-01-11
  • 打赏
  • 举报
回复
还没折腾结束啊 vector<string *> + initializer_list + parameter pack expansion
vipcxj 2014-01-11
  • 打赏
  • 举报
回复
引用 5 楼 mougaidong 的回复:
从性能上讲,这个方案有较大损耗。不能成为一个合格的替代方案。 [quote=引用 4 楼 vipcxj 的回复:]


template<typename... TArgsPack>
std::string GetMd5(const TArgsPack&&... args) {
  auto inargs(std::make_tuple(std::forward<TArgsPack>(args)...);
  MD5_CTX ctx;
  unsigned char md5[16];
  MD5_Init(&ctx);
  argnum = sizeof...(inargs);
  for (int i = 0; i < argnum; ++i)
  {
     const int id = i;
     std::string data = std::get<id>(inargs);
     MD5_Update(ctx, data, data.size());
  }
 
  MD5_Final(md5, &ctx);
 
  return std::string(md5, sizeof(md5));
}
这个?
[/quote] 貌似这代码没法编译通过,所以已经不是性能的问题了,我刚刚又找了好多方法,貌似没找到使用递归模板外的遍历元组的方法~
turing-complete 2014-01-11
  • 打赏
  • 举报
回复
从性能上讲,这个方案有较大损耗。不能成为一个合格的替代方案。
引用 4 楼 vipcxj 的回复:


template<typename... TArgsPack>
std::string GetMd5(const TArgsPack&&... args) {
  auto inargs(std::make_tuple(std::forward<TArgsPack>(args)...);
  MD5_CTX ctx;
  unsigned char md5[16];
  MD5_Init(&ctx);
  argnum = sizeof...(inargs);
  for (int i = 0; i < argnum; ++i)
  {
     const int id = i;
     std::string data = std::get<id>(inargs);
     MD5_Update(ctx, data, data.size());
  }
 
  MD5_Final(md5, &ctx);
 
  return std::string(md5, sizeof(md5));
}
这个?
vipcxj 2014-01-11
  • 打赏
  • 举报
回复


template<typename... TArgsPack>
std::string GetMd5(const TArgsPack&&... args) {
  auto inargs(std::make_tuple(std::forward<TArgsPack>(args)...);
  MD5_CTX ctx;
  unsigned char md5[16];
  MD5_Init(&ctx);
  argnum = sizeof...(inargs);
  for (int i = 0; i < argnum; ++i)
  {
     const int id = i;
     std::string data = std::get<id>(inargs);
     MD5_Update(ctx, data, data.size());
  }
 
  MD5_Final(md5, &ctx);
 
  return std::string(md5, sizeof(md5));
}
这个?
taodm 2014-01-11
  • 打赏
  • 举报
回复
那就看你啥时候反应过来了。
turing-complete 2014-01-11
  • 打赏
  • 举报
回复
如果这样可以,我就用std::initializer_list了。我不想给调用者增加任何使用负担。
引用 1 楼 taodm 的回复:
有必要那么复杂么,vector<strig>就搞定了。
taodm 2014-01-11
  • 打赏
  • 举报
回复
有必要那么复杂么,vector<strig>就搞定了。

65,187

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧