zmiana typow parameter pack dla std::tuple

0

Mam pewne meta informacje w std::tuple, powiedzmy meta<T>, tupla wyglada tak:

std::tuple<meta<A>, meta<B>, meta<C>> meta_info;

chce teraz napisac funkcje tworzaca tuple innych typow na podstawie tej wyzej, takich, ze:

std::tuple<actual<A>, actual<B>, actual<C>> actual_info = some_func(meta_info);

I jakos sie zawiesilem, nie mam zupelnie pomyslu jak do tego podejsc. Sama funkcja musi z kazdego elementu meta_info wziac odpowiednie informacje i umiescic je w konstruktorze typow actual w nowej tupli.

2

O ile dobrze rozumiem to co chcesz zrobić jest dość proste:

template<typename T> struct meta{};
template<typename T> struct actual{};

namespace detail{
template<typename T> struct convert_tuple;

template<typename... Ts>
struct convert_tuple<std::tuple<meta<Ts>...>> {
	using type = std::tuple<actual<Ts>...>;
};

}

template<typename T>
using convert_tuple_t = typename detail::convert_tuple<T>::type;

using foo = std::tuple<meta<int>, meta<int>, meta<std::string>>;
using bar = convert_tuple_t<foo>;

static_assert(std::is_same<bar, std::tuple<actual<int>, actual<int>, actual<std::string>>>::value, "");

edit: dobra, zedytowałeś - z dedukcją z szablonu funkcji powinno być jeszcze łatwiej:

template<typename T> struct meta{};
template<typename T> struct actual{};


template<typename... Ts>
auto some_func(std::tuple<meta<Ts>...> const&) -> std::tuple<actual<Ts>...>{
	return {};
}

int main()
{
	std::tuple<meta<int>, meta<int>, meta<std::string>> meta_info;
	std::tuple<actual<int>, actual<int>, actual<std::string>> actual_info = some_func(meta_info);
}
0

Generalnie tak, tylko poza okresleniem typu potrzebuje jeszcze faktycznie utworzenie nowej tupli na podstawie tej pierwszej.

O widzisz. :-) Dokladnie o to mi chodzilo. Dedukcja typu i sama funkcja mi sie przydadza. Po calym dniu pisania kodu jakos calkowicie wylaczylo mi sie myslenie. Dzieki!

0

Może i głupie pytanie
ale jakie jest tego praktyczne wykorzystanie, takie przykładowe

bo sam głupi jestem i nie potrafię znaleźć/wymyslić

0

Odgrzewam troche temat, troche go komplikujac... zalozmy, ze nie mam prostego mapowania base<T> -> instance<T> tylko chce zrobic "powazniejsza" konwersje. Powiedzmy typ base ma wiecej meta parametrow.

template<typename A, typename B, int C> struct base {};

i na jego podstawie chce budowac tuple typow instance wybierajac (oczywiscie podczas kompilacji;)) sobie ktorys z tych parametrow, np B, tj.: base<A, B, C> -> instance<B>. Lub tez nawet uzywac do konstrukcji instancji typow instance elementow typu base, np. instance<typename T> ma pole value (powiedzmy int). Obrazowo: base<A, B, C> -> instance<B>(C).

edit: na razie mam tyle:

#include <iostream>
#include <tuple>
using namespace std;
 
template<typename A, typename B, int C>
struct base {
    static constexpr auto Value = C;
    using type_A = A;
    using type_B = B;
};
 
template<typename T>
struct instance {
    instance () : v (0) {}
    instance (const T& v) : v(v) {}
    int v;
};
 
template<typename T, size_t N>
struct type_generator
{
    using rest_tuple = typename type_generator<T, N-1>::type;
    using current_type = instance<typename std::tuple_element<N, T>::type::type_A>;
 
    using type = decltype(
        std::tuple_cat(
            std::declval<rest_tuple>(),
            std::declval<std::tuple<current_type>>()
        )
    );
};
 
template<typename T>
struct type_generator<T, 0>
{
    using current_type = instance<typename std::tuple_element<0, T>::type::type_A>;
    using type = std::tuple<current_type>;
};
 
template<typename M>
auto instantiate(const M &m) -> typename type_generator<M, std::tuple_size<M>::value - 1>::type
{
}
 
int main() {
    tuple<base<int, float, 1>, base<float, double, 2>> a;
 
    static_assert(
    	std::is_same<
    		type_generator<decltype(a), tuple_size<decltype(a)>::value - 1>::type,
    		tuple<instance<int>, instance<float>>
    	>::value == true);
    return 0;
}

zawiesilem sie na implementacji instantiate(), chce wziac do inicjalizacji obiektow instance wartosc Value z base.

0

Z tego co kojarzę nie zainstancjonujesz instance w czasie kompilacji bo to jest non-literal

0

tutaj znalazlem cos ciekawego: http://stackoverflow.com/questions/28410697/c-convert-vector-to-tuple (najwyzej punktowana odpowiedz)
troche wypadlem z obiegu jezeli chodzi o C++ zwlaszcza 11 i nie do konca lapie ten trick z index_sequence. Potrzebowalbym dokladnie cos takiego tylko zeby funktor F byl parametryzowany podczas kompilacji a nie dostawal argument "size_t".

0

Nie do końca rozumiem co chcesz osiągnąć. Masz tupla base<...> i oczekujesz, że Twój type_generator wygeneruje to samo? Czy ten static_assert jest tylko dla zmyłki?

0

generator poprawnie generuje juz typ z tupli base<A, B, C> na tuple instance<A> w zaleznosci od using current_type = instance<typename std::tuple_element<N, T>::type::type_A>;
moge sobie wziac np. type_B i wtedy generuje mi tuple instance<B> z tupli base<A, B, C>

Odnosnie "btw, to raczej kwalifikuje się na osobny temat" - jest sens robic nowy watek na forum?

0
int main()
{
	tuple<base<int, float, 1>, base<float, double, 2>> a;
	type_generator<decltype(a), 1>::type new_tuple;

//	static_assert(is_same<decltype(new_tuple), tuple<instance<int>, instance<double>>::value);
}

Czy do czegoś takiego dążysz?

icek napisał(a):

jest sens robic nowy watek na forum?

tak. Pytanie uzyskało odpowiedź. Nic nie szkodzi podlinkować do poprzedniego tematu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1