2013-04-04 5 views
6

Wie erbt ich Konstrukteure aus einer Vorlage Basisklasse, ohne die Vorlage Argumente zu wiederholen (und ohne Makros):Erben Konstruktoren von Template-Basisklasse ohne wiederholende Template-Argumente?

Zum Beispiel dies nicht funktioniert (GCC 4.8 verwendet wird):

template <typename T> 
struct base {}; 

template <typename U> 
struct derived : base<U> { 
    using base::base; 
}; 

Es tut arbeiten, wenn ich die Template-Argumente der Basisklasse wiederholen:

template <typename T> 
struct base {}; 

template <typename U> 
struct derived : base<U> { 
    using base<U>::base; 
}; 

Das Problem ist, dass „U“ etwas sehr komplex sein könnte, und das ist lästig und fehleranfällig zu wiederholen. Zum Beispiel ist hier einer meiner ursprünglichen motivierende Beispiele:

#include <boost/multi_index_container.hpp> 
#include <boost/multi_index/key_extractors.hpp> 
#include <boost/multi_index/ordered_index.hpp> 
#include <boost/multi_index/sequenced_index.hpp> 

using namespace boost::multi_index; 

struct as_list_tag {}; 
struct as_set_tag {}; 

template <typename T> 
struct unique_list : multi_index_container < 
    T, 
    indexed_by < 
     sequenced<tag<as_list_tag>>, 
     ordered_unique<tag<as_set_tag>, identity<T>> 
    > 
> { 
    using multi_index_container < 
     T, 
     indexed_by < 
      sequenced<tag<as_list_tag>>, 
      ordered_unique<tag<as_set_tag>, identity<T>> 
     > 
    > 
    ::multi_index_container; 
    using as_list = as_list_tag; 
    using as_set = as_set_tag ; 
}; 

landete ich um diese Arbeit von einem Makro:

#define MAKE_UNIQUE_LIST(template_params...)\ 
template <typename T>\ 
struct unique_list : multi_index_container template_params\ 
{\ 
    using multi_index_container template_params ::multi_index_container;\ 
    using as_list = as_list_tag;\ 
    using as_set = as_set_tag ;\ 
}; 

MAKE_UNIQUE_LIST(< 
    T, 
    indexed_by < 
     sequenced<tag<as_list_tag>>, 
     ordered_unique<tag<as_set_tag>, identity<T>> 
    > 
>) 
#undef MAKE_UNIQUE_LIST 

Gibt es einen besseren Weg, dies zu nähern? Ein Syntax-Trick fehlt mir? =)

+0

'typedef base übergeordnet;' –

+0

@MooingDuck Sie müssen es immer noch mindestens zweimal wiederholen (einmal im Ableiten und einmal in 'using', um Konstruktoren zu erben). – Zereges

Antwort

3

Es ist nicht perfekt, aber man konnte eine Klasse, die Ihre Art erzeugt:

template <typename T> 
struct unique_list_base { 
    typedef multi_index_container < 
     T, 
     indexed_by < 
      sequenced<tag<as_list_tag>>, 
      ordered_unique<tag<as_set_tag>, identity<T>> 
     > 
    > type; 
}; 

template <typename T> 
struct unique_list : unique_list_base<T>::type { 
    using unique_list_base<T>::type::multi_index_container; 
    using as_list = as_list_tag; 
    using as_set = as_set_tag ; 
}; 
+0

Über den Typnamen vor der unique_list_base :: type GCC sagt: 'Schlüsselwort 'Typname' in diesem Kontext nicht erlaubt (die Basisklasse ist implizit ein Typ)' – wjl

+0

Nach dem Entfernen der zusätzlichen Typname und Fixieren ich Typo, wo ich mich selbst verwirrte, Ich konnte diese Arbeit machen. Vielen Dank! – wjl

+4

@wjl Sie können es weiter vereinfachen, indem Sie 'template mit unique_list_base = multi_index_container <...>;' verwenden. –

2

Nur Daniel Frey Lösung zu markieren, da er nicht die Mühe gemacht hat eine vollständige Antwort zu geben: Template-Deklaration mit (aka Template Typdef) ist der Weg zu gehen.

template <typename T> 
using unique_list_base = 
    multi_index_container < 
     T, 
     indexed_by < 
      sequenced<tag<as_list_tag>>, 
      ordered_unique<tag<as_set_tag>, identity<T>> 
     > 
    >; 

template <typename T> 
struct unique_list : unique_list_base<T> { 
    using unique_list_base<T>::multi_index_container; 
    using as_list = as_list_tag; 
    using as_set = as_set_tag ; 
}; 

Auf diese Weise können Sie von der struct und alle zugehörigen Text loszuwerden, die häufig mit dem C++ 03 foobar<T>::type Idiom verwendet wurden.

+0

Schön. Ich benutze in letzter Zeit sehr viel, und ich sehe, dass es wieder nützlich ist! =) – wjl

+0

Noch besser, dies erlaubt mir, die geerbte Konstruktor-Zeile in 'using unique_list_base :: unique_list_base;' zu ändern, was verständlicher ist. – wjl

2

Ganz einfach:

template <typename U, typename thebase=base<U>> 
struct derived : thebase { 
    using thebase::thebase; 
}; 

Der Nachteil ist, dass es die externe Schnittstelle der Vorlage ändert zwei Vorlagenargumente zu haben. Sie können das wie folgt lösen:

template <typename U, typename thebase=base<U>> 
struct derived_impl : thebase { 
    using thebase::thebase; 
}; 
template<typename U> 
using derived = derived_impl<U>; 
0

Eigentlich scheint es, dass MSVC, als zu gcc Gegensatz erfordert nicht einmal die Vorlage Argument zu wiederholen: man konnte nur schreiben „mit Basis :: base“.