【问题标题】:Pack expansion calling templated method in a function template在函数模板中调用模板化方法的包扩展
【发布时间】:2017-03-30 07:13:43
【问题描述】:

上下文:从模板函数调用模板类的模板方法时传递的参数包(甚至不是模糊的扩展规则),以上所有都涉及非类型可变参数。

Q1:允许以下代码编译(并希望按预期工作)的语法是什么?

Q2:你会推荐我读什么来更好地了解这个[expletive deleted] 包扩展。 (Alexandrescu 的 variadic are funadic 仅此而已,cppreference 对此并没有帮助。是的,我知道,没有任何帮助的风险是实际的

template<
  typename T, typename ProcR,
  T... which,
  bool maxesInclusive=false,
  T... available
>
void process_ranged_queries(
  const std::vector<std::size_t>& mins, const std::vector<std::size_t>& maxes,
  const Accumulator<T, available...>& src, // a templated class with a templated method
  std::function<ProcR(std::unordered_map<T,std::size_t>)> processor,
  std::vector<ProcR>& results
) {
  const std::size_t rangeLen=std::min(mins.size(), maxes.size());
  if(rangeLen>0){
    const std::size_t srcLen=src.size();
    results.clear();
    results.reserve(rangeLen);
    typename decltype(src)::map_o_prefix_sums prefixSums;


    // HERE!!!
    src.prepare_prefix_sums<which...>(prefixSums); // OOOPPPSssshhh! Why? How???
    // etc
  }
}

在带有--std=c++11 的 linux (ubuntu) 上的 gcc 5.4.1 吐出以下错误:

../main.cpp: In function ‘void process_ranged_queries(const std::vector<long unsigned int>&, const std::vector<long unsigned int>&, const Accumulator<T, available ...>&, std::function<ProcR(std::unordered_map<T, long unsigned int>)>, std::vector<ProcR>&)’:
../main.cpp:483:34: error: expected ‘;’ before ‘...’ token
     src.prepare_prefix_sums<which...>(prefixSums);
                                  ^
../main.cpp:483:50: error: parameter packs not expanded with ‘...’:
     src.prepare_prefix_sums<which...>(prefixSums);
                                                  ^
../main.cpp:483:50: note:         ‘which’

godbold for the entire code - 尽管它是不可编译的(只有上面的 2 个错误,别担心)

作为参考,我也在这里发布了整个代码:

#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <functional>

template <typename T, T... categories>
class Accumulator {
  static const std::unordered_set<T> catset;

  std::unordered_map<T, std::vector<bool>> marks_;
  std::size_t size_;

  void check(T val) {
    if(catset.find(val)==catset.end()) {
      throw std::logic_error("Unavailable cat (pick a dog)");
    }
  }
public:
  Accumulator(std::size_t size) : marks_(), size_(size) {
    for(auto c : catset) {
      marks_[c]=std::vector<bool>(size, false);
    }
  }

  std::size_t size() const {
    return this->size_;
  }

  void clear() {
    for(auto kvit : this->marks_) {
      kvit.second.clear(); // sets the size to 0
      kvit.second.resize(this->size_, false); // refills to size with false
    }
  }

  bool marked(T which, std::size_t i) const {
    // later we may go with DEBUG/NDEBUG and use/not-use check and at()/[]
    bool ret=false;
    check(which);
    ret=this->marks_.find(which)->second.at(i);
    return ret;
  }


  void mark(T which, std::size_t i, bool value=true) {
    check(which);
    this->marks_.find(which)->second.at(i)=value;
  }

  // can I go with a templated version for which? Yes I can!
  template <T which> void mark(std::size_t i, bool value=true) {
    check(which);
    this->marks_.find(which)->second.at(i)=value;
  }

  // Well, maybe I can go with a variable templated version!
  // *clickety-click* Well, yea, compiles and works!! Waddayaknow?!
  using map_o_prefix_sums=std::unordered_map<T, std::vector<std::size_t>>;

  template <T... which>
  void prepare_prefix_sums(map_o_prefix_sums& cumulativeCounts) {
    cumulativeCounts.clear();
    // d'oh...!!! for(auto c : which...) {
    constexpr T cats[]={ which... };
    for(auto c : cats) {
      check(c);
      const std::vector<bool>& ticks=this->marks_[c]; // source

      cumulativeCounts[c]=std::vector<std::size_t>(); // destinations
      std::vector<std::size_t>& counts=cumulativeCounts[c];
      counts.reserve(this->size_);
      std::size_t sumSoFar=0;
      for(bool tick : ticks) {
        if(tick) {
          sumSoFar++;
        }
        counts.push_back(sumSoFar);
      }
    }
  }
};


template <typename T, T...cats>
const std::unordered_set<T> Accumulator<T, cats...>::catset={cats...};

template<
  typename T, typename ProcR,
  T... which,
  bool maxesInclusive=false,
  T... available
>
void process_ranged_queries(
  const std::vector<std::size_t>& mins, const std::vector<std::size_t>& maxes,
  const Accumulator<T, available...>& src,
  std::function<ProcR(std::unordered_map<T,std::size_t>)> processor,
  std::vector<ProcR>& results
) {
  const std::size_t rangeLen=std::min(mins.size(), maxes.size());
  if(rangeLen>0){
    const std::size_t srcLen=src.size();
    results.clear();
    results.reserve(rangeLen);
    typename decltype(src)::map_o_prefix_sums prefixSums;
    src.prepare_prefix_sums<which...>(prefixSums); // OOOPPPSssshhh! Why? How???
    // etc
  }
}



int main() {
  std::string s="GATACA";

  std::size_t len=s.length();

  Accumulator<char, 'A', 'C', 'T', 'G'> sumer(s.length());
  for(std::size_t i=0; i<len; i++) {
    sumer.mark(s[i], i);
  }
  sumer.clear();
  for(std::size_t i=0; i<len; i++) {
    switch(s[i]) {
    case 'A':
    case 'a':
      sumer.mark<'A'>(i);
      break;
    case 'G':
    case 'g':
      sumer.mark<'G'>(i);
      break;
    case 'T':
    case 't':
      sumer.mark<'C'>(i);
      break;
    case 'C':
    case 'c':
      sumer.mark<'C'>(i);
      break;
    default:
      break;
    }
  }

  decltype(sumer)::map_o_prefix_sums resultsHere;
  sumer.prepare_prefix_sums<'A', 'C'>(resultsHere); // works well here, the pack is fully specified
  return 0;
}

【问题讨论】:

    标签: c++ c++11 templates


    【解决方案1】:

    依赖模板函数需要使用template关键字

    src.template prepare_prefix_sums<which...>(prefixSums); // OOOPPPSssshhh! Why? How???
    

    您可以查看this 问题及其答案以获得更详细的解释。

    【讨论】:

    • 感谢您的解决方案和参考
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-12
    • 1970-01-01
    • 2021-09-20
    相关资源
    最近更新 更多