2016-01-10 2 views
1

Я пытаюсь найти хорошее решение для следующей задачи:Найти максимальный размер контейнера C++

Я хочу, чтобы реализовать функцию, которая принимает переменное число аргументов контейнера и возвращает размер самого большого контейнера. Вот пример:

std::vector<std::string> vStr(2, "foo"); 
std::vector<int> vInt(1, 123); 
std::vector<double> vDouble(3, 1.1); 
std::list<char> lChar(4, '*'); 
// or even more container 

size_t uiMaxSize = getMaxContainerSize(vStr, vInt, vDouble, lChar /*, ...*/); 

в этом случае getMaxContainerSize должна возвращать 4, потому что lChar имеет самый большой размер 4.

Я уже реализовал этот обходной путь с помощью cstdarg:

#include <cstdarg> 
... 
size_t getMaxContainerSize(int iCnt, ...) 
{ 
    size_t uiMaxSize = 0; 
    va_list ap; 
    va_start(ap, iCnt); 
    for(int i=0; i<iCnt; i++) 
    { 
    size_t uiTempSize = va_arg(ap, size_t); 
    uiMaxSize = uiMaxSize<uiTempSize ? uiTempSize : uiMaxSize; 
    } 
    va_end(ap); 
    return uiMaxSize; 
} 
... 
size_t uiMaxSize = getMaxContainerSize(4, vStr.size(), vInt.size(), vDouble.size(), lChar.size()); 

Но с этим я должен ввести .size() для каждого контейнера, и я также должен указать количество контейнеров. Я также не люблю использовать C-файлы в программах на C++, и я спрашиваю себя, есть ли лучший способ реализовать это. Может быть, с помощью какого-то класса и перегрузок operator<<(), так что я могу ввести что-то вроде этого:

MaxSizeFinder cFinder; 
cFinder << vStr << vInt << vDouble << lChar; 
size_t uiMaxSize = cFinder.getResult(); 

Как вы думаете, что-то, как это возможно? Какие-либо предложения?

спасибо.

+1

Почему бы вам никогда не захотеть этого? Но я уверен, что он разрешится с помощью шаблона переменных аргументов. –

ответ

7

Используйте VARIADIC шаблон:

template<typename... Conts> 
std::ptrdiff_t getMaxContainerSize(const Conts&... conts) { 
    return std::max({conts.size()...}); 
} 

При передаче контейнеров в качестве аргументов, компилятор выведет список типов для Conts. Каждый параметр функции будет const <deduced type> & *. Использование conts.size()... расширяется до conts1.size(), conts2.size(), ..., contsN.size(), где conts# - это каждый аргумент функции. Оказывается, std::max имеет удобную перегрузку, которую вы можете делегировать.

Есть несколько ключевых преимущества над переменными числом шаблонов функций C переменного числа:

  • Они типобезопасны - компилятор гарантированно жалуется, когда типы не совпадают, и вам не нужен формат строка или что-то еще.
  • Функция знает, сколько аргументов было передано, и вы можете получить ее с помощью sizeof...(Conts).
  • Ничего особенного не происходит с аргументами при входе. В вариационной функции char будет int к тому времени, когда функция должна будет выбрать его, среди прочих.
  • Вам не нужно явно указывать какие-либо типы при использовании аргументов. Это означает, что вы можете принять бесконечное количество типов, а не предопределенный список (думаю, printf).

Наконец, в комментарии, возвращаемый тип был изменен на знаковый тип, который в основном выступает в качестве подписанного аналога size_t (вроде нестандартного ssize_t).


Для будущего доказательства ответа, то в скорое время будет std::size для более общего способа получить необходимый размер контейнера:

using std::size; 
return std::max({size(conts)...}); 

Это расширяет аналогичным выше: size(conts1), size(conts2), ..., size(contsN)


* Обычно пачки параметров используются с T&&... с std::forward вместо const T&.... Это потенциально купит вам что-то с сторонними классами, которые имеют более эффективную функцию size, когда используемым объектом является rvalue. Тем не менее, это добавляет сложности вообще для низкой вероятности в любой выгоде.

+0

Переименовать, рассмотреть стандартные функции библиотеки 'getsin' и' getcos'. –

+0

Введите тип результата, лучше сделайте это 'ptrdiff_t' (в отличие от неподписанного типа). Нет смысла поощрять ошибки вползать, повторяя исторические ошибки стандартной библиотеки. Это решение (без знака) было принято в совершенно другой день и возраст, где имелся один бит размера адреса. –

+1

@ Cheersandhth.-Alf, Извините, мне не хватает того, с чем вы сталкиваетесь с 'getin' и' getcos'. Однако я могу изменить тип возврата. Я предпочитаю сами подписываемые типы, я просто придерживался того же типа, что и у OP. Можно было бы ожидать, что функция, которая сравнивает размеры контейнера, возвращает тот же тип, что и размеры контейнеров, а не подписанный аналог. – chris