Эта make_vector
представляет собой функцию, которая принимает любое количество аргументов и идеально передает их в вектор.
// get the first type in a pack, if it exists:
template<class...Ts>
struct first {};
template<class T, class...Ts>
struct first<T,Ts...>{
using type=T;
};
template<class...Ts>
using first_t=typename first<Ts...>::type;
// build the return type:
template<class T0, class...Ts>
using vector_T =
typename std::conditional<
std::is_same<T0, void>::value,
typename std::decay<first_t<Ts...>>::type,
T0
>::type;
template<class T0, class...Ts>
using vector_t = std::vector< vector_T<T0, Ts...> >;
// make a vector, non-empty arg case:
template<class T0=void, class...Ts, class R=vector_t<T0, Ts...>>
R make_vector( Ts&&...ts ) {
R retval;
retval.reserve(sizeof...(Ts)); // we know how many elements
// array unpacking trick:
using discard = int[];
(void)discard{0,((
retval.emplace_back( std::forward<Ts>(ts) )
),void(),0)...};
return retval; // NRVO!
}
// the empty overload:
template<class T>
std::vector<T> make_vector() {
return {};
}
использовать:
std::vector<std::unique_ptr<test1>> vec =
make_vector(
std::move(u1), std::move(u2)
);
живой пример
Я его немного отполировал. Он выведет возвращаемый тип, если вы передадите ему 1 или более аргументов и не передадите ему тип. Если вы передадите ему тип, он будет использовать этот тип. Если вы не передадите ему тип или какие-либо аргументы, он будет жаловаться. (если вы пересылаете пакеты или храните их в определенном типе, я всегда даю ему тип).
Можно сделать еще один шаг, где мы делаем вывод типа возвращаемого значения, чтобы исключить требование указывать тип даже в пустом случае. Это может потребоваться в вашем случае использования, я не знаю, но это соответствует тому, что вам не нужно указывать тип {}
, поэтому я подумал, что выброшу его:
template<class...Ts>
struct make_vec_later {
std::tuple<Ts...> args; // could make this `Ts&&...`, but that is scary
// make this && in C++14
template<class T, size_t...Is>
std::vector<T> get(std::index_sequence<Is...>) {
return make_vector<T>(std::get<Is>(std::move(args))...);
}
// make this && in C++14
template<class T>
operator std::vector<T>(){
return std::move(*this).template get<T>( std::index_sequence_for<Ts...>{} );
}
};
template<class...Ts>
make_vec_later<Ts...> v(Ts&&...ts) {
return {std::tuple<Ts...>(std::forward<Ts>(ts)...)};
}
это зависит от функции index_sequence
С++ 14, но ее легко переписать на С++ 11, если ваш компилятор еще не имеет ее. Просто погуглите о переполнении стека, существует множество реализаций.
Теперь синтаксис выглядит так:
std::vector<std::unique_ptr<test1>> vec =
v(std::move(u1));
где список аргументов может быть пустым.
Живой пример
Поддержка распределителей вариантов остается на усмотрение пользователя. Добавьте к make_vector
еще один тип с именем A
и установите по умолчанию void
. Если он недействителен, замените его на std::allocator<T>
для любого типа T
, выбранного для вектора. В версии вывода возвращаемого типа сделайте что-то подобное.
person
Yakk - Adam Nevraumont
schedule
30.04.2015