Я думаю, я понимаю, что вы хотите. std::pair
имеет похожую функцию:
std::pair<T, U> p(std::piecewise_construct
, std::forward_as_tuple(foo, bar)
, std::forward_as_tuple(qux) );
// p.first constructed in-place as if first(foo, bar) were used
// p.second constructed in place as if second(qux) were used
Как вы можете видеть, у этого есть много преимуществ: имеет место ровно одна конструкция T
и U
, и не требуется, например, T
и U
. MoveConstructible, и это стоит только конструкции из двух мелких кортежей. Это также делает идеальную пересылку. В качестве предупреждения, однако, это значительно сложнее реализовать без наследования конструкторов, и я буду использовать эту функцию, чтобы продемонстрировать возможную реализацию кусочно-конструктора, а затем попытаюсь сделать его вариационную версию.
Но, во-первых, полезная утилита, которая всегда пригодится, когда задействованы различные пакеты и кортежи:
template<int... Indices>
struct indices {
using next = indices<Indices..., sizeof...(Indices)>;
};
template<int Size>
struct build_indices {
using type = typename build_indices<Size - 1>::type::next;
};
template<>
struct build_indices<0> {
using type = indices<>;
}
template<typename Tuple>
constexpr
typename build_indices<
// Normally I'd use RemoveReference+RemoveCv, not Decay
std::tuple_size<typename std::decay<Tuple>::type>::value
>::type
make_indices()
{ return {}; }
Так что теперь, если у нас есть using tuple_type = std::tuple<int, long, double, double>;
, тогда make_indices<tuple_type>()
возвращает значение типа indices<0, 1, 2, 3>
.
Во-первых, не вариадный случай кусочной конструкции:
template<typename T, typename U>
class pair {
public:
// Front-end
template<typename Ttuple, typename Utuple>
pair(std::piecewise_construct_t, Ttuple&& ttuple, Utuple&& utuple)
// Doesn't do any real work, but prepares the necessary information
: pair(std::piecewise_construct
, std::forward<Ttuple>(ttuple), std::forward<Utuple>(utuple)
, make_indices<Ttuple>(), make_indices<Utuple>() )
{}
private:
T first;
U second;
// Back-end
template<typename Ttuple, typename Utuple, int... Tindices, int... Uindices>
pair(std::piecewise_construct_t
, Ttuple&& ttuple, Utuple&& utuple
, indices<Tindices...>, indices<Uindices...>)
: first(std::get<Tindices>(std::forward<Ttuple>(ttuple))...)
, second(std::get<Uindices>(std::forward<Utuple>(utuple))...)
{}
};
Давайте попробуем добавить это в свой миксин:
template<template<typename> class... Mixins>
struct Mix: Mixins<Mix<Mixins...>>... {
public:
// Front-end
template<typename... Tuples>
Mix(std::piecewise_construct_t, Tuples&&... tuples)
: Mix(typename build_indices<sizeof...(Tuples)>::type {}
, std::piecewise_construct
, std::forward_as_tuple(std::forward<Tuples>(tuples)...)
, std::make_tuple(make_indices<Tuples>()...) )
{
// Note: GCC rejects sizeof...(Mixins) but that can be 'fixed'
// into e.g. sizeof...(Mixins<int>) even though I have a feeling
// GCC is wrong here
static_assert( sizeof...(Tuples) == sizeof...(Mixins)
, "Put helpful diagnostic here" );
}
private:
// Back-end
template<
typename TupleOfTuples
, typename TupleOfIndices
// Indices for the tuples and their respective indices
, int... Indices
>
Mix(indices<Indices...>, std::piecewise_construct_t
, TupleOfTuples&& tuple, TupleOfIndices const& indices)
: Mixins<Mix<Mixins...>>(construct<Mixins<Mix<Mixins...>>>(
std::get<Indices>(std::forward<TupleOfTuples>(tuple))
, std::get<Indices>(indices) ))...
{}
template<typename T, typename Tuple, int... Indices>
static
T
construct(Tuple&& tuple, indices<Indices...>)
{
using std::get;
return T(get<Indices>(std::forward<Tuple>(tuple))...);
}
};
Как вы можете видеть, я поднялся на один уровень выше с этими кортежами кортежей и кортежей индексов. Причина в том, что я не могу выразить и сопоставить тип, такой как std::tuple<indices<Indices...>...>
(что означает соответствующий пакет, объявленный как? int...... Indices
?), И даже если я сделал расширение пакета, не предназначено для работы с многоуровневым слишком много расширения пакета Возможно, вы уже догадались, но упаковка всего этого в кортеж, связанный с его индексами, - это мой образ действий, когда дело доходит до решения такого рода задач ... У этого есть недостаток, однако это не конструкция на месте, и теперь Mixins<...>
должны быть MoveConstructible.
Я бы тоже рекомендовал добавить конструктор по умолчанию (т.е. Mix() = default;
), потому что использование Mix<A, B> m(std::piecewise_construct, std::forward_as_tuple(), std::forward_as_tuple());
выглядит глупо. Обратите внимание, что такое объявление по умолчанию не даст конструктора по умолчанию, если любой из Mixin<...>
не является DefaultConstructible.
Код был протестирован со снимком GCC 4.7 и работает дословно, за исключением этого sizeof...(Mixins)
неудача.