如何编写一个可以以类型安全方式遍历泛型类型的函数 [英] how do I write a function that can iterate over a generic type in a typesafe way

查看:190
本文介绍了如何编写一个可以以类型安全方式遍历泛型类型的函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想编写一个函数,它可以以类型安全的方式在给定的泛型类型上输入迭代器。一个可能的用例是编写一个像accumulate / map / fold这样的函数:

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?

以前问过这里

推荐答案

我想我理解你的问题,我可以想到两种不同的方法,有利弊:

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

[1]为迭代器使用第三个模板类型,例如ITER。优点是更容易的代码,工作与更多的集合类型,较少的限制。缺点是,不捕获ITER和V之间的依赖性约束,即ITER必须是迭代类型V的迭代器,即V = ITER :: value_type。

[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]显式调用依赖类型,而不是创建新的模板参数。它更准确地捕获依赖类型,减少模板参数的数量。缺点是,它依赖于可能不是标准的集合的类型声明(如果ITER没有子类型ITER :: value_type,或者它的命名方式不同)。你将在这里使用kewyword类型名作为依赖类型。
这里编译器可以更好地处理编译错误,但是请注意,您几乎不会得到关于类型错误的任何反馈,除非您实际实例化它。所以你需要用2/3具体类型来测试代码。

[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.

C ++代码说明了这两种方法。 BTW为什么要使用typename,我认为应该只是template< class V,..。 typename用于依赖类型(例如函数accumulate2)

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
}

这篇关于如何编写一个可以以类型安全方式遍历泛型类型的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆