При наличии кортежа с векторами, содержащими различных типов как извлечь вектор с минимальным размером?
Вы не можете Выне может напрямую.
Поскольку они являются разными типами, решение основывается на значениях (не на типах), поэтому вы не можете определить тип извлеченного времени компиляции (std::tuple
не может быть constexpr
), а C ++ является языком со строгой типизацией.
best простейшая вещь, которую вы можете сделать, это извлечь index вектора с минимальным размером.Потому что в этом случае извлеченное значение является целым числом (std::size_t
, например), и вы можете перебирать векторы в кортеже, чтобы выбрать тот с меньшим количеством элементов.
Отличается, если вам нужно извлечьstd::array
с минимальным размером
auto t = std::make_tuple(std::array<int, 2u>({1,2}),
std::array<double, 3u>({1.0, 2.0, 3.0}));
, поскольку размер (2u
для первого, 3u
для второго) является известным временем компиляции, поэтому вы можете выбрать время компиляции второго массива.
Если вы можете использовать C ++ 17, вы можете использовать std::variant
, то есть тип, который может содержать все типы вашего кортежа.
Как указывает Caleth (спасибо), если вы можете использовать толькоC ++ 11 / C ++ 14 с расширенными библиотеками, вы можете использовать boost::variant
.Но я не знаю этого, поэтому я не могу показать вам конкретный пример (но вы можете увидеть ответ Калета)
Ниже приведен пример с кортежем двух типов
template <typename T1, typename T2>
std::variant<T1, T2> getLess (std::tuple<T1, T2> const & tp)
{
std::variant<T1, T2> v;
if ( std::get<0>(tp).size() < std::get<1>(tp).size() )
v = std::get<0>(tp);
else
v = std::get<1>(tp);
return v;
}
int main ()
{
std::vector<int> vi {1, 2, 3};
std::vector<double> vd {1.0, 2.0};
auto gl = getLess(std::make_tuple(vi, vd));
}
Это работает с кортежем двух типов.Но с кортежем N-типов (с высотой N
) становится сложным, потому что вы не можете записать что-то как
auto min_length = std::get<0>(tp).size();
auto min_index = 0u;
for ( auto ui = 1u ; ui < N ; ++ui )
if ( std::get<ui>(tp).size() < min_length )
{
min_length = std::get<ui>(tp).size();
min_index = ui;
}
, потому что вы не можете передать std::get<>()
значение времени выполнения как ui
.
Та же проблема при назначении варианта.Вы не можете просто написать
v = std::get<min_index>(tp);
, потому что min_index
является значением времени выполнения.
Вы должны пройти через switch()
switch ( min_length )
{
case 0: v = std::get<0>(tp); break;
case 1: v = std::get<1>(tp); break;
case 2: v = std::get<2>(tp); break;
case 3: v = std::get<3>(tp); break;
case 4: v = std::get<4>(tp); break;
// ...
case N-1: v = std::get<N-1>(tp); break;
};
или что-то в этом роде.
Как вы видите, все сложнее и сложнее, если вы хотите, чтобы функция getLess()
была переменной.
Для случая с вариадой лучшее, что я могу себе представить(но это решение C ++ 17; см. ответ Калет для решения C ++ 11) заключается в использовании вспомогательной функции и свертывания шаблонов следующим образом.
#include <tuple>
#include <vector>
#include <variant>
#include <iostream>
template <typename ... Ts, std::size_t ... Is>
auto getLessHelper (std::tuple<Ts...> const & tp,
std::index_sequence<0, Is...> const &)
{
std::variant<Ts...> var_ret { std::get<0>(tp) };
std::size_t min_size { std::get<0>(tp).size() };
((std::get<Is>(tp).size() < min_size ? (var_ret = std::get<Is>(tp),
min_size = std::get<Is>(tp).size())
: 0u), ...);
return var_ret;
}
template <typename ... Ts>
auto getLess (std::tuple<Ts...> const & tp)
{ return getLessHelper(tp, std::index_sequence_for<Ts...>{}); }
int main ()
{
std::vector<int> vi {1, 2, 3};
std::vector<double> vd {1.0, 2.0};
std::vector<float> vf {1.0f};
auto gl = getLess(std::make_tuple(vi, vd, vf));
std::cout << std::visit([](auto const & v){ return v.size(); }, gl)
<< std::endl; // print 1, the size() of vf
}