2013-07-14 16 views

Odpowiedz

6

Zakładam, że chcesz to wszystko w czasie kompilacji.

Oto ogólne wyjaśnienie: łączenie krotek jest podobne do łączących się list lub tablic, ponieważ algorytm jest taki sam. Tutaj, podając krotki a i b, wybrałem przeniesienie ostatniego elementu a na początek b i powtarzam do momentu, aż a będzie puste.

Po pierwsze: struktury podstawowe. Poniższa struktura zachowuje pakiet parametrów. Może to być cokolwiek, na przykład krotka:

template<typename... T> 
struct pack 
{ 
    static const unsigned int size = sizeof...(T); 
}; 

Należy pamiętać, że rozmiar paczki jest w nim przechowywany. Nie jest to obowiązkowe, ale jest wygodne dla wyjaśnienia. Funkcja Boost używa struktury boost::tuples::length<T>::value (która jest bardziej szczegółowa).

celu uzyskania dostępu do elementu w i-tego położenia, to zastosowanie struktury podobnej do boost::tuples::element<n, T>:

// Get i-th element of parameter pack 
// AKA 'implementation' 
// Principle: the element i is the first element of the sub-array starting at indice i-1 
template<int n, typename F, typename... T> 
struct element_at : public element_at<n-1, T...> 
{ 
}; 

template<typename F, typename... T> 
struct element_at<0, F, T...> 
{ 
    typedef F type; 
}; 

// Get i-th element of pack 
// AKA 'interface' for the 'pack' structure 
template<int n, typename P> 
struct element 
{ 
}; 

template<int n, typename... T> 
struct element<n, pack<T...>> 
{ 
    typedef typename element_at<n, T...>::type type; 
}; 

Teraz trzeba użyć działanie na niskim poziomie, który jest dodanie jednego elementu na boku paczki (dodawanie po lewej lub po prawej). Tutaj dodając po lewej stronie jest wybrał, ale nie jest to jedyny wybór:

// Concat at left (only for structure 'pack') 
template<typename a, typename b> 
struct tuple_concat_left 
{ 
}; 

template<typename a, typename... b> 
struct tuple_concat_left<a, pack<b...>> 
{ 
    typedef pack<a, b...> type; 
}; 

przypadku szablonów, a nie ulegnie zmianie, a zamiast tego używamy indice wiedzieć, co elementem dodać. Dziedziczenie definiuje typedef, który jest połączeniem wszystkich indeksów po n i drugiej krotce (nie włączając n, i w kolejności). Musimy po prostu połączyć się po elemencie z indeksem n.

// Concat 2 tuples 
template<typename a, typename b, int n = 0, bool ok = (n < a::size)> 
struct tuple_concat : public tuple_concat<a, b, n+1> 
{ 
    typedef typename tuple_concat_left< 
     typename element<n, a>::type, 
     typename tuple_concat<a, b, n+1>::type 
    >::type type; 
}; 

template<typename a, typename b, int n> 
struct tuple_concat<a, b, n, false> 
{ 
    typedef b type; 
}; 

I to wszystko! Live example here.

Teraz, dla krotności szczegółów: zauważyłeś, że nie użyłem boost :: tuple ani std :: tuple. Dzieje się tak dlatego, że wiele implementacji boost tuplesdo nie ma dostępu do szablonów variadic, więc używana jest ustalona liczba parametrów szablonu (domyślnie są to boost::tuples::null_type). Umieszczenie tego bezpośrednio przy szablonach variadycznych jest bólem głowy, a więc potrzebą innej abstrakcji.

Zakładałem również, że możesz użyć C++ 11 (z pytaniem decltype). Łączenie 2 krotek w C++ 03 jest możliwe, ale bardziej powtarzalne i nudne.

można przekonwertować pack do krotki bardzo łatwo: wystarczy zmienić definicję pack:

template<typename... T> 
struct pack 
{ 
    static const unsigned int size = sizeof...(T); 
    typedef boost::tuple<T...> to_tuple; // < convert this pack to a boost::tuple 
}; 
1

C++ 14 oferuje bibliotekę do generowania sekwencji liczb całkowitych w rodzaju kompilacji. Pomaga to manipulować statycznymi sekwencjami, takimi jak krotki i tablice (example). Sekwencja całkowitą można uzyskać

template<size_t... Ints> 
struct integer_sequence {}; 

template<size_t Size, size_t... Ints> 
struct implementation : implementation<Size-1, Size-1, Ints...> {}; 

template<size_t... Ints> 
struct implementation<0, Ints...> 
{ 
    typedef integer_sequence<Ints...> type; 
}; 

template<class... T> 
using index_sequence_for = typename implementation<sizeof...(T)>::type; 

Aby Concat MyTuple i MyType można napisać proste funkcje:

template<typename X, typename Tuple, size_t... Ints> 
auto concat(X x, Tuple t, integer_sequence<Ints...>) 
    -> decltype(std::make_tuple(x, std::get<Ints>(t)...)) 
{ 
    return std::make_tuple(x, std::get<Ints>(t)...); 
} 

template<typename X, typename... T> 
std::tuple<X, T...> concat(X x, std::tuple<T...> t) 
{ 
    return concat(x, t, index_sequence_for<T...>()); 
} 

concat(MyType, MyTuple); 
Powiązane problemy