вычет аргумента с параметрами шаблона шаблона

У меня есть шаблон класса. В этом шаблоне класса я пытаюсь определить шаблон функции-члена, который принимает const_iteratorна коллекции strings. Сама коллекция может быть любой коллекцией StdLib, но реально это будет либо vector или list,

Поскольку коллекция может быть любого типа, я использую template-template Параметр для указания типа коллекции. Однако это всегда будет коллекция string, Я хочу, чтобы вывод аргумента шаблона работал так, чтобы мне не приходилось указывать тип коллекции при вызове функции-члена.

Код, который следует в SSCCE, напоминает мой предполагаемый вариант использования.

Пока что я за определение класса (Live Demo):

template <typename Foo>
struct Gizmo
{
Foo mF;
Gizmo (Foo f) : mF (f) {};

template <template <typename> class Cont> void DoIt(
typename Cont <string>::const_iterator begin,
typename Cont <string>::const_iterator end)
{
stringstream ss;
ss << "(" << this->mF << ")\n";
const std::string s = ss.str();
copy (begin, end, ostream_iterator <std::string> (cout, s.c_str()));
}
};

Компиляция экземпляров шаблона класса завершается успешно:

int main()
{
list <string> l;
l.push_back ("Hello");
l.push_back ("world");

Gizmo <unsigned> g (42);
}

Однако, когда я пытаюсь использовать вывод аргумента (без которого, все это упражнение почти бессмысленно):

g.DoIt (l.begin(), l.end());

GCC жалуется, что не может вывести аргумент шаблона:

prog.cpp: In function ‘int main()’:
prog.cpp:34:28: error: no matching function for call to ‘Gizmo<unsigned int>::DoIt(std::list<std::basic_string<char> >::iterator, std::list<std::basic_string<char> >::iterator)’
g.DoIt (l.begin(), l.end());
^
prog.cpp:34:28: note: candidate is:
prog.cpp:16:49: note: template<template<class> class typedef Cont Cont> void Gizmo<Foo>::DoIt(typename Cont<std::basic_string<char> >::const_iterator, typename Cont<std::basic_string<char> >::const_iterator) [with Cont = Cont; Foo = unsigned int]
template <template <typename> class Cont> void DoIt(
^
prog.cpp:16:49: note:   template argument deduction/substitution failed:
prog.cpp:34:28: note:   couldn't deduce template parameter ‘template<class> class typedef Cont Cont’
g.DoIt (l.begin(), l.end());

в конечном счете все, что меня действительно волнует, это возможность звонить DoIt с начала и конца итераторов на коллекции string, Фактический тип коллекции может быть vector или же listи я не хочу ни указывать аргументы шаблона, ни перегрузку на основе контейнера.

Как я могу заставить это работать?

Обратите внимание, что мой фактический вариант использования будет в C ++ 03. Приветствуются решения C ++ 11, но я смогу принять только решение C ++ 03.

2

Решение

Было несколько проблем. Я исправил параметр шаблона шаблона для вас. Я также изменил сигнатуру метода, чтобы вы могли автоматически выводить типы, но это требует передачи исходной коллекции:

#include <iostream>
#include <vector>
#include <list>
#include <string>
#include <sstream>
#include <iterator>
using namespace std;template <typename Foo>
struct Gizmo
{
Foo mF;
Gizmo (Foo f) : mF (f) {};

template <template <typename T, typename A = allocator<T> > class Cont> void DoIt(
const Cont <string> &, // deduction
const typename Cont <string>::iterator &begin,
const typename Cont <string>::iterator &end)
{
stringstream ss;
ss << "(" << this->mF << ")\n";
const std::string s = ss.str();
copy (begin, end, ostream_iterator <std::string> (cout, s.c_str()));
}
};

int main()
{
list <string> l;
l.push_back ("Hello");
l.push_back ("world");

Gizmo <unsigned> g (42);
g.DoIt (l, l.begin(), l.end());
}

Смотрите, бегите сюда.

2

Другие решения

Кажется, я упускаю суть, но почему ты не можешь сделать это?

template <typename Iterator> void DoIt(
Iterator begin,
Iterator end)
{
// snip
}

// [...]

list <string> l;
l.push_back ("Hello");
l.push_back ("world");
vector <string> v;
v.push_back ("Hello");
v.push_back ("world");

Gizmo <unsigned> g (42);
g.DoIt (l.begin(), l.end());
g.DoIt (v.begin(), v.end());
1

Я утверждаю, что вам на самом деле все равно, если ваш вклад vectorили listили даже контейнер. Я думаю, что все, что вас на самом деле беспокоит, это то, что у вас есть последовательность вещей, которую вы можете перебрать, которые можно преобразовать string, Таким образом, вы должны принять любую пару итераторов, чьи value_type is_convertible в string (Живая демоверсия в Coliru):

template <typename Iter>
typename enable_if<
is_convertible<
typename iterator_traits<Iter>::value_type,string
>::value
>::type DoIt(Iter begin, Iter end) const
{
stringstream ss;
ss << "(" << this->mF << ")\n";
const std::string s = ss.str();
copy (begin, end, ostream_iterator <std::string> (cout, s.c_str()));
}

Я прошу прощения за уродство ограничения, Понятия Lite не могу добраться сюда достаточно скоро для меня.

1

Проблема в том, что для неконстантных строк begin а также end возврат функций string::iterator, но нет string::const_iterator, Вы должны написать аналогичную функцию, только с string::iterator, Или в c ++ 11 вы можете использовать функции cbegin и cend.

0

Это не выводимый контекст, и вы не можете обойти это.

Учитывая итератор, вы просто не можете сказать, к какому контейнеру он принадлежит. Например, необработанный указатель может служить итератором для нескольких типов контейнеров.

К счастью, вы никогда не используете тип контейнера для чего-либо, поэтому вы можете просто выбросить его и параметризировать на итераторе.

Но я использую его, чтобы убедиться, что мой контейнер содержит строки!

Нет, ты не. Кто сказал тебе Foo<string>::iterator разыменование строки (или что она существует, в этом отношении)? Конечно, если это существует, это наверное разыменовывается в строку из-за существующих соглашений, но это ни в коем случае не гарантируется.

0
По вопросам рекламы [email protected]