2013-12-20 15 views
6

Angenommen, dass ich die folgende Klassendefinition haben:Wie erstellt man ein boost :: Tupel mit der angegebenen Anzahl von Elementen (des gleichen Typs)?

template <unsigned int N> 
class foo 
{ 
    boost::tuples::tuple<...> bar; 
}; 

N die Kompilierung-Konstante gegeben, ich möchte die Art von bar erweitern ein Tupel zu sein, die N Elemente eines bestimmten Typs enthält. Das heißt, der Typ foo<2>::bar wäre boost::tuples::tuple<T, T>. Ich schätze, dass ich Boost.MPL dafür verwenden kann, aber ich habe noch nicht die genaue Reihenfolge herausgefunden. Ich glaube, ich könnte tun:

template <typename T, int N> 
struct type_repeater 
{ 
    typedef typename boost::mpl::fold< 
     boost::mpl::range_c<T, 0, N>, 
     boost::mpl::vector<>, 
     boost::mpl::push_back<_1, T> 
    >::type type; 
}; 

So dann zum Beispiel type_repeater<T, 2>::type-boost::mpl::vector<T, T> entspräche. Ich bin mir nur nicht sicher, wie/wenn ich diese Typenliste nehmen und in die Argumentliste eines Tupels einspeisen kann, wie ich will. Ist das möglich?

+0

Sie brauchen keinen Boost dafür, wenn Sie Zugriff auf C++ 11 haben. Wären Sie mit einer Version in Ordnung, die stattdessen C++ 11 verwendet? – OmnipotentEntity

+0

Ich bin offen für die beste Lösung für jeden Fall, aber am Ende werde ich mindestens eine C++ 03-Implementierung benötigen. –

Antwort

3

zu sein, obwohl dies völlig machbar mit variadische Vorlagen und std::tuple, die besten Lösung für das, was Sie wollen, denke ich, ist std::array nur zu verwenden. Wenn Sie einfach einen Container mit N Instanzen von T möchten, ist die Signatur bereits template <typename T, std::size_t N> class array. Ich denke, es passt genau zu Ihrem Bedarf.

gesagt haben, dass, wenn Sie aus irgendeinem Grund wirklich std::tuple wollen Sie es wie so tun können:

#include <tuple> 

/* Forward declaration. */ 
template <std::size_t N, typename T> 
class Tuple; 

/* Convenience type alias. */ 
template <std::size_t N, typename T> 
using TTuple = typename Tuple<N, T>::type; 

/* Base case. */ 
template <typename T> 
class Tuple<0, T> { 
    public: 

    using type = std::tuple<>; 

}; // Tuple<0> 

/* Recursive case. */ 
template <std::size_t N, typename T> 
class Tuple { 
    public: 

    /* Note the use of std::declval<> here. */ 
    using type = decltype(std::tuple_cat(std::declval<std::tuple<T>>(), 
             std::declval<TTuple<N - 1, T>>())); 

}; // Tuple<N, T> 

/* std::declval<> is necessary to support non default constructable classes. */ 
class NoDefault { 
    public: 

    NoDefault() = delete; 

}; // Foo 

/* Sample use. */ 
static_assert(std::is_same<TTuple<2, NoDefault>, 
          std::tuple<NoDefault, NoDefault>>::value, ""); 

int main() {} 

Hinweis: Wenn Sie C++ 11 aber haben Zugang haben keinen Zugang zu zu verstärken, boost::array und boost::tuples::tuple wird anstelle von std::array und std::tuple in Ordnung.

5

Dies scheint ein gutes minimales Beispiel unter Verwendung von C++ 11

#include <tuple> 
template <unsigned int N, typename T> 
struct type_repeater { 
    typedef decltype(std::tuple_cat(std::tuple<T>(), typename type_repeater<N-1, T>::type())) type; 
}; 

template <typename T> 
struct type_repeater<0, T> { 
    typedef decltype(std::tuple<>()) type; 
}; 

int main() { 
    type_repeater<3, float>::type asdf; 
    std::get<0>(asdf); 
    std::get<1>(asdf); 
    std::get<2>(asdf); 
} 
+0

Ok, ich bin fertig damit, diese Antwort zu finden, denke ich. – OmnipotentEntity

+0

Das ist in Ordnung, obwohl es besser sein könnte, da es nur wiederholt Tupel rekursiv verketten. – Rapptz

+0

Dies ist der erste Weg, der Ihnen in den Sinn kam. Haben Sie irgendeine Methode im Sinn, die keine Rekursion verwendet? – OmnipotentEntity

1

Da Sie explizit nach einem Weg fragen mpl :: Vektor in eine Runtime-Container, empfehle ich Ihnen Boosty bleiben und nutzen Fusion as_vector zu machen:

Bei Ihrem ersten Beispiel, in dem Sie mol :: falten bekommen einen mpl :: vector, würden Sie dann verwenden:

boost::fusion::result_of::as_vector< 
    mpl::vector<T, T> 
>::type; 

um ein Fusion Vector zu bekommen, das, was Sie wollen zu sein scheint. Boost Fusion füllt die Lücke zwischen der Kompilierungszeit und der Laufzeitwelt.

Auch das ist vor C++ 11, die immer noch in vielen (vielleicht die meisten?) Projekte wichtig ist.