2017-06-14 59 views
9

Potrzebuję zbudować krotkę n typów. Te typy n są typami wartości n innych typów. Rozważmy następujący fragment:Jak zdefiniować krotkę typów wartości z zestawu parametrów

#include <boost/hana.hpp> 

namespace hana = boost::hana; 

template<class... Types> 
class CartesianProduct 
{ 
public: 
    CartesianProduct(Types... args) : sets(args...) {} 

    hana::tuple<Types...> sets; 
    hana::tuple<Types...::value_type> combination; // does not work obviously... but wo can this be done? 
}; 

Zastosowanie to ma tak: Mijam tej klasy paczkę parametru pojemnikach ewentualnie różnych typów. Klasa umieszcza te pojemniki w krotce sets. Klasa ma także pole combination, które jest krotką tylu elementów, ile kontenerom przekazano klasie. Ale typy elementów są typami wartości różnych pojemników.

Ta klasa jest przeznaczona do leniwego budowania kartezjańskiego produktu przekazywanych do niej pojemników i przechowywania aktualnej kombinacji w combination. Ale w jaki sposób mogę rzeczywiście dostać się do typów wartości kontenerów w wariadowy sposób?

+0

Czy wszystkie typy mają "typ wartości"? – StoryTeller

+0

Cóż, robię to jako warunek wstępny. –

+0

Jeśli napiszesz tę leniwą kartezjańską klasę produktu, byłoby wspaniale, gdybyś mógł wnieść ją z powrotem do Hany. Chciałbym dodać leniwy widok i może być dobrym pomysłem samodzielne wdrożenie 'cartesian_product'. –

Odpowiedz

11

Oczywiście można to zrobić. Trzeba tylko odpowiednio zadeklarować rozszerzenie paczki.

hane::tuple<typename Types::value_type...> combination; 

Należy zwrócić uwagę na wymagane użycie specyfikatora typu. Regułą jest traktowanie nazwy pakietu jako jednego typu. Obowiązują te same ograniczenia składniowe i semantyczne, ponieważ musimy określić, że uzyskujemy dostęp do typu za pomocą operatora rozdzielczości zakresu. Następnie po prostu dodaj rozszerzenie paczki na końcu.

Live Example

#include <vector> 
#include <map> 
#include <tuple> 

template<class... Types> 
class CartesianProduct 
{ 
public: 
    CartesianProduct(Types... args) : sets(args...) {} 

    std::tuple<Types...> sets; 
    std::tuple<typename Types::value_type...> combination; 
}; 


int main() { 
    std::vector<int> i; 
    std::map<int, std::vector<int>> m; 

    CartesianProduct<std::vector<int>, std::map<int, std::vector<int>>> 
     c(i, m); 

    return 0; 
} 
5

Rozszerzenie na prawidłową odpowiedź Narratora (zaakceptować jego odpowiedź proszę):

I łatwiej wizualizować typu tłumaczenia jak to wdrażając je w kategoriach meta tłumaczenia funkcja, na przykład:

#include <vector> 
#include <map> 
#include <tuple> 

namespace metafunction_impl 
{ 
    // meta function taking one type (T) and 'returning' one type. 
    // i.e. a unary metafunction 
    template<class T> struct get_value_type 
    { 
    using result = typename T::value_type; 
    }; 
} 

// provide clean interface to the metafunction 
template<class T> using GetValueType = typename metafunction_impl::get_value_type<T>::result; 

template<class... Types> 
class CartesianProduct 
{ 
public: 
    CartesianProduct(Types... args) : sets(args...) {} 

    std::tuple<Types...> sets; 

    // use my metafunction 
    std::tuple<GetValueType<Types>...> combination; 
}; 


int main() { 
    std::vector<int> i; 
    std::map<int, std::vector<int>> m; 

    CartesianProduct<std::vector<int>, std::map<int, std::vector<int>>> 
     c(i, m); 

    return 0; 
} 
+0

To solidna wizualizacja, dlaczego należy wyobrazić sobie opakowanie jako nazwę jednego typu. Lepsze niż moje podejście do zasady. +1 – StoryTeller