how do I write a function that can iterate over a generic type in a typesafe way [closed]

守給你的承諾、 提交于 2020-01-07 03:51:12

问题


I want to write a function that can input an iterator over a given generic type in a typesafe way. One possible use case would be writing a function like accumulate/map/fold:

#include <iterator>
#include <vector>
#include <functional>

template <typename V, typename K>
K accumulate(
      std::function<K(K, V)> accumulator,
      /* WHAT TYPE DO I PUT HERE */ it,
      /* WHAT TYPE DO I PUT HERE */ end,
      K initial) {
  K sum = initial;
  for (; it != end; ++it) {
    V item = *it;
    sum = accumulator(sum, item);
  }
  return sum;
}

How can I do this in a way that the compiler will check types and all that good stuff?

Previously asked here


回答1:


I think I understood your question, and I can think of two different approaches, both has pros and cons :

[1] Use a 3rd template type for the iterators, say ITER. Advantage is easier code, works with more collection types, less restriction. Disadvantage is, does not capture the dependency constraint between ITER and V, i.e. ITER must be an iterator which iterates over type V, namely V = ITER::value_type.

[2] Explicitly call out the dependent type instead of creating new template param. It captures the dependent types more accurately, less number of template params. Disadvantage is, it relies on the type declaration of the collection which may not be the standard (what if ITER does not have a child type ITER::value_type, or it is named differently ?) . You will use the kewyword typename for the dependent types here. Here the compiler can do better handling of compilation errors, however note that you would hardly get any feedback about type errors unless you actually instantiate it. So you need to test the code with 2/3 concrete types.

The C++ code illustrates both approaches. BTW why are you using typename, I think it should be just "template < class V, ..". typename is used for dependent types (e.g. function accumulate2)

template <class V, class K, class ITER>
K accumulate1(
      std::function<K(K, V)> accumulator,
      ITER it,
      ITER end,
      K initial) {
  K sum = initial;
  for (; it != end; ++it) {
    V item = *it;
    sum = accumulator(sum, item);
  }
  return sum;
}

template <class K, class ITER>
K accumulate2(
      std::function<K(K, typename ITER::value_type)> accumulator,
      ITER it,
      ITER end,
      K initial) {
  K sum = initial;
  for (; it != end; ++it) {
    typename ITER::value_type item = *it;
    sum = accumulator(sum, item);
  }
  return sum;
}

string AppendInt(const string& s, int n) {
  char buffer [65];
  sprintf(buffer, "%s/%d", s.c_str(), n);
  return string(buffer);
}

int main(int argc, char* argv[]) {
  std::function<string(string,int)> fun =
      [](string s, int n) -> string { return AppendInt(s,n); };
  string initial = "x";
  vector<int> array = {13, 24, 50, 64, 32};
  string sum1 = accumulate1(fun, array.begin(), array.end(), initial);
  string sum2 = accumulate2(fun, array.begin(), array.end(), initial);
  printf("accumulate1 : %s\n", sum1.c_str()); // o/p: x/13/24/50/64/32
  printf("accumulate2 : %s\n", sum2.c_str()); // o/p: x/13/24/50/64/32
}



回答2:


Study the patterns used in the containers of the standard library. The problem is you're trying to make explicit a number of types that the container should be defining. In addition, prudent use of auto means you don't have explicit declare some types at all.

template <typename C, typename R>
R accumulate(
      std::function<R(R, C::value_type)> accumulator,
      R initial
) {
  auto sum = initial;
  for (auto it = C.begin(); it != C.end(); ++it) {
    sum = accumulator(sum, *it);
  }
  return sum;
}

By using the container type as your template argument, you can rely upon its value_type definition for type safety on the accumulator function. By using auto for the iterators and using the standard begin() and end() methods, you don't have to even explicitly mention their type. (Just to be sure, they're C::iterator if you needed them.)



来源:https://stackoverflow.com/questions/34301584/how-do-i-write-a-function-that-can-iterate-over-a-generic-type-in-a-typesafe-way

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!