Форум программистов, компьютерный форум CyberForum.ru

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

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

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

07.07.2013, 14:40. Просмотров 1112. Ответов 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;
}
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
07.07.2013, 14:40     Тип контейнера как параметр шаблонной функции
Посмотрите здесь:
Как определить тип возвращаемого значения шаблонной функции по типу итератора (не auto)? C++
Указать тип переменной в шаблонной функции C++
Шаблон как тип контейнера std::set C++
C++ Как правильно реализовать проверку типа передаваемого аргумента в шаблонной функции?
C++ Свой тип как параметр шаблона
Как сделать функцию, которая тип данных использует как параметр? C++
C++ Параметр шаблона класса как собственный тип данных
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
OhMyGodSoLong
~ Эврика! ~
1243 / 992 / 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;
}
Croessmah
Модератор
Эксперт CЭксперт С++
12979 / 7291 / 812
Регистрация: 27.09.2012
Сообщений: 18,007
Записей в блоге: 3
Завершенные тесты: 1
07.07.2013, 14:56     Тип контейнера как параметр шаблонной функции #3
Цитата Сообщение от 0x10 Посмотреть сообщение
Что мешает оставить...
хотя бы это:
Цитата Сообщение от 0x10 Посмотреть сообщение
T itm;
OhMyGodSoLong
07.07.2013, 14:59
  #4

Не по теме:

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

Croessmah
07.07.2013, 15:01
  #5

Не по теме:

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

C++
1
ifs>>v;

ForEveR
В астрале
Эксперт С++
7968 / 4730 / 320
Регистрация: 24.06.2010
Сообщений: 10,539
Завершенные тесты: 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;
}
Tulosba
:)
Эксперт С++
4392 / 3235 / 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, потому что копировать его всё же нельзя (неужели никто не заметил?)
0x10
2459 / 1631 / 238
Регистрация: 24.11.2012
Сообщений: 4,009
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);
}
Olivеr
411 / 407 / 13
Регистрация: 06.10.2011
Сообщений: 830
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 минуту
или я не говорю совсем не о том?))
0x10
2459 / 1631 / 238
Регистрация: 24.11.2012
Сообщений: 4,009
07.07.2013, 20:54     Тип контейнера как параметр шаблонной функции #10
Olivеr, да вот и я о том же. Обрати внимание на 7 строчку в постах 7 и 8 - насколько я понял, это основной затык. Либо я опять чего-то не понимаю.
ForEveR
В астрале
Эксперт С++
7968 / 4730 / 320
Регистрация: 24.06.2010
Сообщений: 10,539
Завершенные тесты: 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 возможна перегрузка.
Olivеr
411 / 407 / 13
Регистрация: 06.10.2011
Сообщений: 830
07.07.2013, 21:53     Тип контейнера как параметр шаблонной функции #12
ForEveR,
C++
1
error: request for member 'push_back' in 'container', which is of non-class type 'int'|
Ну и что тут не так? Или Ваш компилятор такой ошибки не выдает?
ForEveR
В астрале
Эксперт С++
7968 / 4730 / 320
Регистрация: 24.06.2010
Сообщений: 10,539
Завершенные тесты: 3
07.07.2013, 21:58     Тип контейнера как параметр шаблонной функции #13
Olivеr, Не то, что нет функции push_back, а то, что int не является типом "класс". Все вцелом норм, однако, довольно часто использовать SFINAE, вместо ошибки компиляции является несколько профитнее.
Tulosba
:)
Эксперт С++
4392 / 3235 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
07.07.2013, 22:01     Тип контейнера как параметр шаблонной функции #14
Цитата Сообщение от ForEveR Посмотреть сообщение
А во-вторых - данный код будет работать на С++11 совместимом компиляторе
Что-то не получается ...
ForEveR
В астрале
Эксперт С++
7968 / 4730 / 320
Регистрация: 24.06.2010
Сообщений: 10,539
Завершенные тесты: 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/3...move-semantics
Tulosba
07.07.2013, 22:09
  #16

Не по теме:

Цитата Сообщение от ForEveR Посмотреть сообщение
MSVC 2012 компилирует. Ideone нет.
Неожиданно с точки зрения C++11 получилось. Всегда думал, что у gcc дела лучше обстоят с новым стандартом, чем у VS.

ForEveR
В астрале
Эксперт С++
7968 / 4730 / 320
Регистрация: 24.06.2010
Сообщений: 10,539
Завершенные тесты: 3
07.07.2013, 22:11     Тип контейнера как параметр шаблонной функции #17
Tulosba, На ideone не стоит последняя версия gcc. Там что-то около 4.7 насколько я помню.
Tulosba
:)
Эксперт С++
4392 / 3235 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
07.07.2013, 22:13     Тип контейнера как параметр шаблонной функции #18
Цитата Сообщение от ForEveR Посмотреть сообщение
На ideone не стоит последняя версия gcc
4.7.2 пишут. Но даже в этом случае я больше доверял ideone, чем vs.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
07.07.2013, 22:13     Тип контейнера как параметр шаблонной функции
Еще ссылки по теме:
C++ Вызов шаблонной функции
Итераторы в шаблонной функции C++
C++ Создание шаблонной функции
Объявление шаблонной функции C++
Экспортирование шаблонной функции из dll C++

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

Или воспользуйтесь поиском по форуму:
Olivеr
411 / 407 / 13
Регистрация: 06.10.2011
Сообщений: 830
07.07.2013, 22:13     Тип контейнера как параметр шаблонной функции #19
Просто в GCC перемещающие конструкторы для потоков еще не сделаны:
27.5 Iostreams base classes Partial Missing move and swap operations on basic_ios. Missing io_errc and iostream_category. ios_base::failure is not derived from system_error.
http://gcc.gnu.org/onlinedocs/libstd....2011.specific
C++
1
cout << boolalpha << is_move_constructible<istream>::value;
false
GCC 4.8.1
27.9 File-based streams Partial Missing move and swap operations
Yandex
Объявления
07.07.2013, 22:13     Тип контейнера как параметр шаблонной функции
Ответ Создать тему
Опции темы

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