LINUX.ORG.RU

Шаблонная функция. Хочется странного. Что выбрать?

 ,


0

2

Допустим есть функция (что-то вроде std::transform), которая принимает на входе контейнер (либо vector, либо list, либо deque) содержащий элементы типа Х и функцию, которая, в свою очередь, принимает тип Х и возвращает тип Y. На выходе получаем контейнер содержащий элементы типа Y. Вопрос заключает в том, как это лучше реализовать (в плане удобства пользования)?
1. Не важно какой контейнер на входе — всегда возвращать определенный контейнер (например vector):

template<template<class...> class input_sequence, class T, class functor>
std::vector<typename std::result_of<functor(T)>::type> foo(const input_sequence<T>& sequence, functor func)
{
    std::vector<typename std::result_of<functor(T)>::type> result;
    ...
    return result;
}

double bar(int x)
{
    return sqrt(x);
}

std::vector<int> in{1, 2, 3, 4, 5};
auto out = foo(in, bar);
2. Возвращать контейнер того же типа, что и контейнер на входе:
template<template<class...> class input_sequence, class T, class functor>
input_sequence<typename std::result_of<functor(T)>::type> foo(const input_sequence<T>& sequence, functor func)
{
    input_sequence<typename std::result_of<functor(T)>::type> result;
    ...
    return result;
}

double bar(int x)
{
    return sqrt(x);
}

std::vector<int> in{1, 2, 3, 4, 5};
auto out = foo(in, bar);
3. Явно инстанцировать шаблон:
template<class output_sequence, class input_sequence, class functor>
output_sequence foo(const input_sequence& sequence, functor func)
{
    output_sequence result;
    ...
    return result;
}

double bar(int x)
{
    return sqrt(x);
}

std::vector<int> in{1, 2, 3, 4, 5};
auto out = foo<std::vector<double>>(in, bar);
За изобретение костылей прошу сильно не пинать!

Я ничего не понял и код не читал, но почему просто в цикле не пройтись по контейнеру и не вернуть новый контейнер?

DELIRIUM ★★★★★ ()
Ответ на: комментарий от DELIRIUM

Ну, на месте троеточия и есть проход в цикле. Даже два цикла. Функция применяется довольно часто с разными функторами и типами контейнеров (в основном vector, но бывает и list попадается). Вопрос в том, как правильнее реализовать возврат контейнера из функции.

baldman88 ()
Ответ на: комментарий от baldman88

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

baldman88 ()

что-то вроде std::transform

Ну так и сделай на итераторах.

mironov_ivan ★★★★★ ()
Ответ на: комментарий от mironov_ivan

Сначала именно так и хотел. Но стало лень создавать новый контейнер и резервировать место в нем. Так, при использовании auto, получается проще (вроде как). Немного перефразирую вопрос: какие могут возникнуть проблемы при такой реализации.

baldman88 ()

Она должна принимать либо OutputIterator и складывать результаты в него (хинт: есть всяческие insert_iteratator и back_insert_iterator'ы которым можно наполнять любые контейнеры), либо ничего не принимать, и пусть вызывающая сторона делает что ей надо сразу в функторе.

slovazap ★★★★★ ()

Двухэтажные шаблоны и «удобно» - это несовместимые понятия. Может быть, ты ещё осилишь их написание. Но когда придётся иметь дело с сообщениями об ошибках, будешь каждый раз плакать.

Освой динамическую типизацию.

Самое главное - быстрота шаблонов иллюзорна. Динамически типизированный luajit часто обгоняет С, потому что его компактное ядро полностью помещается в процессорном кеше. Многоэтажные шаблоны порождают много кода, который не помещается в процессорном кеше. Так что их польза для быстродействия вообще неочевидна.

ИМХО.

den73 ★★★★★ ()
Ответ на: комментарий от den73

Освой динамическую типизацию.

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

luajit

Если ты не знаешь, luajit перед компиляцией в машкод выделяет в программе статически типизированные участки. Собственно, все JIT динамических языков так поступают. Так что где генерируется меньше кода - большой вопрос.

tailgunner ★★★★★ ()
Последнее исправление: tailgunner (всего исправлений: 2)

По теме - все три приведенных способа говно, правильный ответ дал slovazap.

tailgunner ★★★★★ ()
Ответ на: комментарий от den73

Самое главное - быстрота шаблонов иллюзорна.

Хоть один пример бы увидеть, где шаблонный код медленнее динамического.

anonymous ()
Ответ на: комментарий от den73

LOR, как всегда, в своем стиле. На поставленный вопрос о том, как пользоваться одним сортом говна, предлагают пользоваться другим сортом. Если будет нужна динамическая типизация, то я лучше возьму python. Там хоть есть то, что нужно для моих целей (numpy и т.д.).

baldman88 ()

Я бы сделал одну реализацию с OutputIterator, и перегрузку/функцию рядом, которая отдаёт вектор.

Первое нужно для универсальности, второе — для удобства.

vzzo ★★★ ()
Ответ на: комментарий от den73

Освой динамическую типизацию.
быстрота шаблонов иллюзорна.

Эксперт в треде.

DarkEld3r ★★★★★ ()
Ответ на: комментарий от den73

Динамически типизированный luajit часто обгоняет С

и тут вы такой с пруфами)

next_time ★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.