Я все еще работаю над перегрузкой функции 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
}
Как я путаю эти функции? Спасибо!
Небольшая альтернатива тому, что обсуждается в комментариях:
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;
Ну, как объяснено в предыдущих замечаниях, компилятор не может определить тип контейнера итератора, заданный в качестве параметра Sum
,
Тем не менее, можно использовать тот факт, что std::map<X,Y>::iterator::value_type
это пара значений std::pair<XX, YY>
, Конечно, это не ограничит желаемую специализацию Sum
в std::map
итераторы, но для любого контейнерного итератора, возвращающего пару элементов (например, std::vector< std::pair<std::string, double> >
.)
Если это вас не беспокоит, или если что-то вроде std::vector< std::pair<std::string, double> >
следует использовать ту же специализацию, тогда следующий код, похоже, даст желаемые результаты в вашем случае:
#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());
}