Как создать кортеж оболочки из кортежа реализатора?

У меня есть несколько классов-реализаторов (impls) и несколько оболочек для пользователя, реализованных на C ++. Я хочу держать impls и обертки в двух разных кортежах, чтобы я мог инициализировать свои impls одним выделением. (У меня есть и другие причины :).

Дело в том, что класс кортежей стандартной библиотеки visual studio 2012 не позволяет мне создавать свой кортеж-обертку без конструктора копий оберток с ссылками на const. к сожалению, мне нужно const_cast в этом случае, например:

#include <iostream>
#include <type_traits>
#include <tuple>
#include <typeinfo>

template <typename Member>
struct A
{
A(Member& m) : member(m)
{ std::cout << typeid(Member).name() << " MMBR " << member << std::endl; }

A(const Member& m) : member(const_cast<Member&>(m))
{ std::cout << typeid(Member).name() << " CMBR " << member << std::endl; }

void Print()
{
std::cout << typeid(Member).name() << " PRNT " << member << std::endl;
}

Member& member;//yes I need to hold this as a mutable reference
};

int main()
{
typedef std::tuple<A<int>, A<double>, A<short>> WrapperTuple;
typedef std::tuple<int, double, short> Tuple;

Tuple t(0, 1, 2);
WrapperTuple w(t);

std::get<1>(w).Print();
return std::cin.get();
}

Приведенный выше код компилируется и запускается, как задумано, но если я удаляю / комментирую const-ref-ctor класса-оболочки A, ни мой компилятор VS2012, ни мой компилятор gcc4.7.2 не компилируют код. (1) Что я делаю не так?

Поскольку у меня нет хорошей документации для c ++ 11, я предполагаю, что переменная копия ctor кортежа принимает только const ref другого кортежа. Если это так, (2), почему класс кортежей не имеет такого ctor? Я имею в виду основную причину.

Подводя итог, я хочу объединить все impls и оболочки в кортеж, чтобы я мог выделить одно действие (то есть make_shared). Кортеж является обязательным, потому что я написал несколько помощников, чтобы я мог искать по типу во время компиляции (например, Get<A<int>>(w)) (3) Есть ли удобный способ хранить ссылку на импл, чтобы мне не нужно было выделять каждый импл отдельно?

1

Решение

Копирующий конструктор std::tupleдаже конвертирующий, очевидно, копирует все элементы, и, поскольку копия не должна изменять скопированный элемент, они помечаются как const, Такое поведение вполне разумно, большую часть времени.

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

template<unsigned...> struct seq{};
template<unsigned N, unsigned... Is>
struct gen_seq : gen_seq<N-1, N-1, Is...>{};
template<unsigned... Is>
struct gen_seq<0, Is...> : seq<Is...>{};

namespace aux{
template<class... Ts, unsigned... Is>
std::tuple<Ts&...> tie_all_(std::tuple<Ts...>& other, seq<Is...>){
return std::tie(std::get<Is>(other)...);
}
} // aux::

template<class... Ts>
std::tuple<Ts&...> tie_all(std::tuple<Ts...>& other){
return aux::tie_all_(other, gen_seq<sizeof...(Ts)>());
}

Код используется так: WrapperTuple w(tie_all(t));, Теперь вы можете избавиться от Member const& конструктор.

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

template<class... Ts>
std::tuple<A<Ts>...> wrap_all(std::tuple<Ts...>& other){
return tie_all(other);
}
// ...
auto w(wrap_all(t));

И если у вас есть разные классы-обертки:

template<template<class> class Wrapper, class... Ts>
std::tuple<Wrapper<Ts>...> wrap_all_in(std::tuple<Ts...>& other){
return tie_all(other);
}
// ...
auto w = wrap_all_in<A>(t);
3

Другие решения

Почему бы тебе просто не создать wrapped_tuple шаблон, который оборачивает весь tuple и обеспечивает реализацию get? Кажется излишним хранить ссылки на отдельные элементы кортежа, так как кортеж имеет фиксированную компоновку, и компилятор может выдавать тривиальный код для ссылки на отдельный элемент, заданный ссылкой на кортеж.

Например (и делать это без вариадических шаблонов, что немного раздражает):

template<typename Tuple> class wrapped_tuple;

template<size_t I, typename Tuple>
typename std::tuple_element<I, Tuple>::type&
Get(wrapped_tuple<Tuple>& w) {
return std::get<I>(w.tuple_);
}

template<typename Tuple> class wrapped_tuple {
template<size_t I, typename Uple>
friend typename std::tuple_element<I, Uple>::type&
::Get(wrapped_tuple<Uple>& w);
public:
wrapped_tuple(Tuple& t) : tuple_(t) {}
private:
Tuple& tuple_;
};

template<typename Tuple>
wrapped_tuple<Tuple> wrap_tuple(Tuple& tup) {
return wrapped_tuple<Tuple>(tup);
}

Вот на идеоне.

0

По вопросам рекламы [email protected]