Форум программистов, компьютерный форум, киберфорум
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
PG94
2 / 2 / 0
Регистрация: 15.01.2012
Сообщений: 181
#1

Тип контейнера как параметр шаблонной функции - C++

07.07.2013, 14:40. Просмотров 1310. Ответов 18
Метки нет (Все метки)

Добрый день. Подскажите, пожалуйста, можно ли передавать тип контейнера как параметр в шаблонную функцию? Если да, то как это делается?
Есть функция (см. код ниже), и в результате хотелось бы, чтобы она могла работать со всеми контейнерами, имеющими метод push_back().
C++
1
2
3
4
5
6
7
8
9
10
11
template<class T>
ifstream fill_v(vector<T>& v, const string& from)
{
    ifstream ifs(from);
    if (!ifs) throw runtime_error("can't open input file");
 
    T itm;
    while (ifs>>itm) 
        v.push_back(itm);
    return ifs;
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
07.07.2013, 14:40
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Тип контейнера как параметр шаблонной функции (C++):

Как определить тип возвращаемого значения шаблонной функции по типу итератора (не auto)? - C++
Здравствуйте. Есть шаблонная функция (например, суммирования). Входные значения два итератора -- начало конец. template &lt;typename...

Указать тип переменной в шаблонной функции - C++
Доброго времени суток, форумчане! Есть переменная. Есть шаблонная функция. Как в качестве параметра шаблона мне указать тип данных, к...

Шаблон как тип контейнера std::set - C++
template&lt;class T&gt; int func(T&amp;, int); typedef std::ostream_iterator&lt;int&gt; out_in; int main() { int xx{1, 2, 3, 4, 5, 6, 7, 7,...

Как правильно реализовать проверку типа передаваемого аргумента в шаблонной функции? - C++
Доброго времени суток, уважаемые форумчане! Пытаюсь реализовать проверку типа аргумента, передаваемого шаблонной функции. Использую...

Свой тип как параметр шаблона - C++
Есть вопрос по коду: #include &lt;iostream&gt; #include &lt;memory&gt; #include &lt;vector&gt; using namespace std; template&lt;class T&gt; class...

Как сделать функцию, которая тип данных использует как параметр? - C++
Хочу сделать функцию function(&quot;переменные&quot;, &quot;тип данных&quot;). Можно ли это реализовать? А именно, более подробно что-то в этом роде: ...

18
OhMyGodSoLong
~ Эврика! ~
1244 / 993 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
07.07.2013, 14:53 #2
Плохо №1:
C++
1
2
3
4
5
6
7
8
9
10
11
template<class T, template <class> class Container>
ifstream fill_v(Container<T>& v, const string& from)
{
    ifstream ifs(from);
    if (!ifs) throw runtime_error("can't open input file");
 
    T itm;
    while (ifs>>itm) 
        v.push_back(itm);
    return ifs;
}
Плохо №2:
C++
1
2
3
4
5
6
7
8
9
10
11
template<class T, class Container>
ifstream fill_v(Container& v, const string& from)
{
    ifstream ifs(from);
    if (!ifs) throw runtime_error("can't open input file");
 
    T itm;
    while (ifs>>itm) 
        v.push_back(itm);
    return ifs;
}
Окей №3:
C++
1
2
3
4
5
6
7
8
9
10
11
template<class T, class... Rest, template <class, class...> class Container>
ifstream fill_v(Container<T, Rest...>& v, const string& from)
{
    ifstream ifs(from);
    if (!ifs) throw runtime_error("can't open input file");
 
    T itm;
    while (ifs>>itm) 
        v.push_back(itm);
    return ifs;
}
2
Croessmah
Ушел
Эксперт CЭксперт С++
13554 / 7705 / 872
Регистрация: 27.09.2012
Сообщений: 19,006
Записей в блоге: 3
Завершенные тесты: 1
07.07.2013, 14:56 #3
Цитата Сообщение от 0x10 Посмотреть сообщение
Что мешает оставить...
хотя бы это:
Цитата Сообщение от 0x10 Посмотреть сообщение
T itm;
1
OhMyGodSoLong
07.07.2013, 14:59
  #4

Не по теме:

Хорошо №4: жуткий ужас с тайп-трейтами и std::enable_if.

0
Croessmah
07.07.2013, 15:01
  #5

Не по теме:

OhMyGodSoLong, можно взять decltype, что несколько упростит дело
а еще можно перегрузить операторы << и >> для контейнера, а в данной функции только

C++
1
ifs>>v;

0
ForEveR
В астрале
Эксперт С++
7983 / 4742 / 321
Регистрация: 24.06.2010
Сообщений: 10,545
Завершенные тесты: 3
07.07.2013, 19:51 #6
boost::type_erasure

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
template<class C, class T>
struct has_push_back
{
    static void apply(C& cont, const T& arg) { cont.push_back(arg); }
};
 
namespace boost {
namespace type_erasure {
template<class C, class T, class Base>
struct concept_interface<has_push_back<C, T>, Base, C> : Base
{
    void push_back(typename as_param<Base, const T&>::type arg)
    { call(has_push_back<C, T>(), *this, arg); }
};
}
}
 
using namespace boost::type_erasure;
 
template<typename T>
ifstream fill_v(any<has_push_back<_self, T>, _self&> v, const string& from)
{
    ifstream ifs(from);
    if (!ifs) throw runtime_error("can't open input file");
 
    T itm;
    while (ifs>>itm) 
        v.push_back(itm);
    return ifs;
}
0
Tulosba
:)
Эксперт С++
4397 / 3233 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
07.07.2013, 20:19 #7
А нужно ли иметь в контейнере элементы именно типа T? Может быть достаточно, чтобы тип T успешно преобразовывался при добавлении в контейнер, тогда всё элементарно:
C++
1
2
3
4
5
6
7
8
9
10
template<class T, class C>
void fill_v( C& c, const std::string& from)
{
    std::ifstream ifs(from);
    if (!ifs) throw std::runtime_error("can't open input file");
 
    T itm;
    while (ifs>>itm) 
        c.push_back(itm);
}
Использование:
C++
1
2
3
4
5
    std::vector<int> v;
    std::list<double> l;
 
    fill_v<int, std::vector<int> >( v, "f1"); // Типы совпадают
    fill_v<int, std::list<double> >( l, "f2"); // int преобразуется в double
И ещё я убрал возврат ifstream, потому что копировать его всё же нельзя (неужели никто не заметил?)
0
0x10
2479 / 1654 / 248
Регистрация: 24.11.2012
Сообщений: 4,099
07.07.2013, 20:29 #8
Ну сложно для моих маленьких мозгов... Зачем городить такие шаблоны...
C++
1
2
3
4
5
6
7
8
9
10
template<class T>
void fill_v( T& c, const std::string& from)
{
    std::ifstream ifs(from.c_str());
    if (!ifs) return;
 
    typename T::value_type itm;
    while (ifs>>itm) 
        c.push_back(itm);
}
2
Olivеr
412 / 408 / 13
Регистрация: 06.10.2011
Сообщений: 832
07.07.2013, 20:34 #9
А что если сделать по-простому, вот так:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <vector>
#include <set>
#include <queue>
#include <deque>
#include <list>
#include <stack>
using namespace std;
 
template <typename Container>
void push_back(Container &container)
{
    container.push_back(1);
}
 
int main()
{
    list<int>   a;
    vector<int> b;
    set<int>    d;
    stack<int>  e;
    queue<int>  f;
    deque<int>  h;
 
    push_back(a);
    push_back(b);
    push_back(d);
    push_back(e);
    push_back(f);
    push_back(h);
    return 0;
}


Компилятор в любом случае выдаст ошибки. Так зачем, собственно говоря, мучится?

|13|error: 'class std::set<int>' has no member named 'push_back'|
|13|error: 'class std::stack<int>' has no member named 'push_back'|
|13|error: 'class std::queue<int>' has no member named 'push_back'|
Добавлено через 1 минуту
или я не говорю совсем не о том?))
0
0x10
2479 / 1654 / 248
Регистрация: 24.11.2012
Сообщений: 4,099
07.07.2013, 20:54 #10
Olivеr, да вот и я о том же. Обрати внимание на 7 строчку в постах 7 и 8 - насколько я понял, это основной затык. Либо я опять чего-то не понимаю.
0
ForEveR
В астрале
Эксперт С++
7983 / 4742 / 321
Регистрация: 24.06.2010
Сообщений: 10,545
Завершенные тесты: 3
07.07.2013, 21:49 #11
Цитата Сообщение от Tulosba Посмотреть сообщение
И ещё я убрал возврат ifstream, потому что копировать его всё же нельзя (неужели никто не заметил?)
Ну во-первых наверняка не заметили.
А во-вторых - данный код будет работать на С++11 совместимом компиляторе (move семантика же, переменная временная, следовательно будет вызван конструктор перемещения).

Добавлено через 3 минуты
Olivеr, 0x10, А теперь давайте пошлем вызовем данную функцию например так

C++
1
2
3
4
5
6
7
8
9
10
11
template <typename Container>
void push_back(Container &container)
{
    container.push_back(1);
}
 
int main()
{
   int value = 0;
   push_back(value);
}
Очень понятная ошибка будет?) В случае OhMyGodSoLong просто не произойдет инстанцирование функции, ибо тип не сможет быть выведен, это даже не говоря о том, что в ваших случаях возможен только 1 вариант данной функции (не учитывая специализацию) в варианте же OhMyGodSoLong возможна перегрузка.
1
Olivеr
412 / 408 / 13
Регистрация: 06.10.2011
Сообщений: 832
07.07.2013, 21:53 #12
ForEveR,
C++
1
error: request for member 'push_back' in 'container', which is of non-class type 'int'|
Ну и что тут не так? Или Ваш компилятор такой ошибки не выдает?
0
ForEveR
В астрале
Эксперт С++
7983 / 4742 / 321
Регистрация: 24.06.2010
Сообщений: 10,545
Завершенные тесты: 3
07.07.2013, 21:58 #13
Olivеr, Не то, что нет функции push_back, а то, что int не является типом "класс". Все вцелом норм, однако, довольно часто использовать SFINAE, вместо ошибки компиляции является несколько профитнее.
0
Tulosba
:)
Эксперт С++
4397 / 3233 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
07.07.2013, 22:01 #14
Цитата Сообщение от ForEveR Посмотреть сообщение
А во-вторых - данный код будет работать на С++11 совместимом компиляторе
Что-то не получается ...
0
ForEveR
В астрале
Эксперт С++
7983 / 4742 / 321
Регистрация: 24.06.2010
Сообщений: 10,545
Завершенные тесты: 3
07.07.2013, 22:02 #15
Tulosba, MSVC 2012 компилирует. Ideone нет. Доступа к новому gcc сейчас не имею, завтра проверю, возможно я ошибаюсь, но насколько я помню, перемещение локальных объектов всецело допустимо.

Perhaps surprisingly, automatic objects (local variables that are not declared as static) can also be implicitly moved out of functions:
C++
1
2
3
4
5
unique_ptr<Shape> make_square()
{
    unique_ptr<Shape> result(new Square);
    return result;   // note the missing std::move
}
How come the move constructor accepts the lvalue result as an argument? The scope of result is about to end, and it will be destroyed during stack unwinding. Nobody could possibly complain afterwards that result had changed somehow; when control flow is back at the caller, result does not exist anymore! For that reason, C++11 has a special rule that allows returning automatic objects from functions without having to write std::move. In fact, you should never use std::move to move automatic objects out of functions, as this inhibits the "named return value optimization" (NRVO).
http://stackoverflow.com/questions/3106110/what-are-move-semantics
1
07.07.2013, 22:02
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
07.07.2013, 22:02
Привет! Вот еще темы с ответами:

Параметр шаблона класса как собственный тип данных - C++
Приветствую. Такой вопрос: как перегрузить операторы класса-шаблона, где в качестве аргумента шаблона выступает собственный тип данных....

Объявление шаблонной функции - C++
Здравствуйте, встретил в учебнике это: template &lt;typename Type, int size&gt; Type min( Type (&amp;r_array) ) { //... }

Создание шаблонной функции - C++
Создать шаблонную функцию, изменяющий порядок элементов таким образом: первая половина списка смещается в конец, а вторая в начало. К...

Вызов шаблонной функции - C++
Что я делаю не так? есть функция: template &lt;class T&gt; T rFF(string input_file) { string tmp; ifstream file(input_file); file...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru