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

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

Восстановить пароль Регистрация
 
PG94
2 / 2 / 0
Регистрация: 15.01.2012
Сообщений: 181
07.07.2013, 14:40     Тип контейнера как параметр шаблонной функции #1
Добрый день. Подскажите, пожалуйста, можно ли передавать тип контейнера как параметр в шаблонную функцию? Если да, то как это делается?
Есть функция (см. код ниже), и в результате хотелось бы, чтобы она могла работать со всеми контейнерами, имеющими метод 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     Тип контейнера как параметр шаблонной функции
Посмотрите здесь:

C++ Ошибка вызова шаблонной функции
C++ Создание шаблонной функции
C++ Не вызывается специализация шаблонной функции
Объявление шаблонной функции C++
Присваивание по ссылке в шаблонной функции C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 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
Модератор
Эксперт С++
 Аватар для Croessmah
11822 / 6801 / 769
Регистрация: 27.09.2012
Сообщений: 16,869
Записей в блоге: 2
Завершенные тесты: 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
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 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
:)
Эксперт С++
4378 / 3221 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
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
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
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
 Аватар для 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
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
07.07.2013, 20:54     Тип контейнера как параметр шаблонной функции #10
Olivеr, да вот и я о том же. Обрати внимание на 7 строчку в постах 7 и 8 - насколько я понял, это основной затык. Либо я опять чего-то не понимаю.
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 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
 Аватар для 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
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
07.07.2013, 21:58     Тип контейнера как параметр шаблонной функции #13
Olivеr, Не то, что нет функции push_back, а то, что int не является типом "класс". Все вцелом норм, однако, довольно часто использовать SFINAE, вместо ошибки компиляции является несколько профитнее.
Tulosba
:)
Эксперт С++
4378 / 3221 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
07.07.2013, 22:01     Тип контейнера как параметр шаблонной функции #14
Цитата Сообщение от ForEveR Посмотреть сообщение
А во-вторых - данный код будет работать на С++11 совместимом компиляторе
Что-то не получается ...
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 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
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
07.07.2013, 22:11     Тип контейнера как параметр шаблонной функции #17
Tulosba, На ideone не стоит последняя версия gcc. Там что-то около 4.7 насколько я помню.
Tulosba
:)
Эксперт С++
4378 / 3221 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
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++ Вызов шаблонной функции
Шаблон как тип контейнера std::set C++
C++ Экспорт шаблонной функции из DLL

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

Или воспользуйтесь поиском по форуму:
Olivеr
 Аватар для 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     Тип контейнера как параметр шаблонной функции
Ответ Создать тему
Опции темы

Текущее время: 21:03. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru