【问题标题】:Overloaded Sum Function, Confusing List/Vector with Map重载的 Sum 函数,将 List/Vector 与 Map 混淆
【发布时间】:2012-09-22 02:37:29
【问题描述】:

我仍在努力重载 Sum 函数,该函数可以与向量/列表或映射一起使用。我的 sum 函数的向量/列表版本工作正常,我认为我的地图版本代码相当不错,但是当我测试它时,编译器似乎认为我正在尝试调用函数的列表/向量版本,并引发一些编译器错误。相关代码如下:

template <typename T>
const double Sum(typename T start_iter, typename T end_iter)
{// code...
}

template <typename T>
const double Sum(map<typename T, double> start_iter, map<typename T, double> end_iter)
{// different code...
}

int main()
{

map<string, double> test_map; // construct empty map

test_map["Line1"] = 10; // add some data
test_map["Line2"] = 15; 

Sum(test_map.begin(),test_map.end()) // this tries to call the list/vector version of sum
}

我如何混淆这些功能?谢谢!

【问题讨论】:

  • 首先,您在第二个声明中缺少两个 ::iterators。 map&lt;typename T, double&gt; 中的 typename 也是不必要的。其次,在map&lt;T, double&gt;::iterator 中,T 处于不可演绎的上下文中,所以你不走运。您可以根据std::iterator&lt;Iter&gt;::value_type 是否为pair 来尝试重载。
  • 那么,应该更像这样吧? const double Sum&lt;map&lt;T,double&gt;&gt;(map&lt;typename T, double&gt;::iterator start_iter, map&lt;typename T, double&gt;::iterator end_iter)
  • @Clark:是的,但也要注意avakar关于推导T的说法。如果您将函数称为Sum(test_map.begin(),test_map.end()),则编译器无法通过模板参数推导得出T应该成为string。你可以称它为Sum&lt;string&gt;(test_map.begin(),test_map.end())
  • 无论您如何编写它,它都不会起作用,因为编译器将无法通过匹配map&lt;T, double&gt;::iteratormap&lt;string, double&gt;::iterator 来推断Tstring。这就是不可演绎上下文的含义。
  • 原因,顺便说一句,标准中没有说明map&lt;string,double&gt;::iterator 是否与something_else::iterator 是同一类型。 iterator 只是一个类中的 typedef,它是一个类型的 name。模板参数推导适用于传递的类型,而不是它们的名称。 “在某个类中显示为 typedef”不是标准关注的类型的属性。

标签: c++ templates stl map overloading


【解决方案1】:

对 cme​​ts 中讨论的内容稍作替代:

template <typename Vt>
struct getter
{
  Vt operator()(const Vt& v)
  {
    return v;
  }
};

template <typename F, typename G>
struct getter<std::pair<F, G> >
{
  G operator()(const std::pair<F, G>& v)
  {
    return v.second;
  }
};


template <typename Iterator>
int sum(Iterator it, Iterator end)
{
  int r = 0;
  for(; it != end; ++it)
    r += getter<typename Iterator::value_type>()(*it);
  return r;
}

现在sum 函数并不关心它正在迭代什么,只需依靠适当的getter 来获取值...

例如:

  std::map<int, int> f;
  f[1] = 3;
  f[2] = 6;
  f[3] = 12;
  f[4] = 24;

  std::vector<int> g;
  g.push_back(4);
  g.push_back(8);
  g.push_back(16);
  g.push_back(32);

  std::cout << sum(f.begin(), f.end()) << std::endl;
  std::cout << sum(g.begin(), g.end()) << std::endl;

【讨论】:

  • +1,很好的解决方案,不涉及enable_if(这是我会使用的:))。
  • 虽然要注意使用迭代器调用sumvector&lt;pair&lt;int,int&gt;&gt; 现在会将所有第二个元素相加。在提问者的原始代码中,它可能无法编译(因为Sum 的主体会尝试添加元素),这可能是可取的。
【解决方案2】:

好吧,如前所述,编译器无法推断出作为Sum的参数给出的迭代器的容器类型。

但是,可以使用std::map&lt;X,Y&gt;::iterator::value_type 是一对值std::pair&lt;XX, YY&gt; 的事实。当然,这不会将Sum 的期望特化限制为std::map 迭代器,而是限制任何返回一对元素的容器迭代器(例如std::vector&lt; std::pair&lt;std::string, double&gt; &gt;。)

如果这不打扰您,或者像 std::vector&lt; std::pair&lt;std::string, double&gt; &gt; 这样的东西应该使用相同的专业化,那么下面的代码似乎可以在您的情况下给出所需的结果:

#include <map>
#include <string>
#include <iostream>
#include <cassert>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/remove_reference.hpp>


// a small structure to 
template <class U>
struct is_a_key_pair_it
{
  typedef boost::false_type type;
};

template <class A, class B>
struct is_a_key_pair_it< std::pair<A, B> >
{
  typedef boost::true_type type;
};

// using boost::disable_if to avoid the following code to be instanciated 
// for iterators returning a std::pair
template <typename T>
const double Sum(T start_iter, T end_iter, 
  typename boost::disable_if<
    typename is_a_key_pair_it<
      typename boost::remove_reference<typename T::value_type>::type 
    >::type >::type * dummy = 0)
{
  // code...
  std::cout << "non specialized" << std::endl;
  return 0;
}

// using boost::enable_if to limit the following specializing of Sum
// to iterators returning a std::pair
template <typename T>
const double Sum(T start_iter, T end_iter, 
  typename boost::enable_if<
    typename is_a_key_pair_it<
      typename boost::remove_reference<typename T::value_type>::type 
    >::type >::type * dummy = 0)
{
  // different code...
  std::cout << "specialized" << std::endl;
  return 1;
}




int main()
{
  typedef std::map<std::string, double> map_t;

  // check
  assert(is_a_key_pair_it<map_t::iterator::value_type>::type::value);
  // works also for const_iterators
  assert(is_a_key_pair_it<map_t::const_iterator::value_type>::type::value);

  map_t test_map;
  test_map["Line1"] = 10; // add some data
  test_map["Line2"] = 15; 

  double ret = Sum(test_map.begin(),test_map.end()); 
}

【讨论】:

    猜你喜欢
    • 2018-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多