Frage

Ich habe einen Code geschrieben, in dem ich eine Klasse habe, die Mixins als variadische Vorlagenparameter akzeptieren kann. Ich brauche jedoch auch die Mixins, um über das CRTP -Idiom auf die Basisklasse zugreifen zu können. Hier ist ein minimales Beispiel, das nicht genau das tun kann, was ich will:

template <template <class> class... Mixins>
class Foo : Mixins<Foo<Mixins...>>... {};

Ein Mixin, an den ich möglicherweise passieren könnte Foo wird im Allgemeinen mehrere Vorlagenparameter wie SO haben:

template <class Derived, class Type1, class Type2>
class Bar
{
    Derived& operator()()
    {
        return static_cast<Derived&>(*this);
    }
};

Wie kann ich mich ändern Foo Damit ich es von einer Reihe von Basisklassen erben kann, wo ich die von jeder Basisklasse akzeptierten Vorlagenparameter steuere? Wenn ich Hand habe Foo Eine Liste von Vorlagen-Template-Parametern sowie eine Liste von Argumenten, die an sie weitergegeben werden sollen, sehe ich nicht, wie ich jeden Vorlagen-Template-Parameter mit seinen Argumenten assoziieren kann. Bisher dachte ich an so etwas, aber ich weiß nicht, wie ich vorgehen würde.

template <template <class...> class T,
    template <class...> class... Ts>
class Foo : /* How do I retrieve the arguments? */
War es hilfreich?

Lösung

Ich bin mir nicht ganz sicher, ob ich das Problem verstanden habe. Bitte lassen Sie mich es umformeln, damit wir auf dem richtigen Fuß beginnen können.

Sie müssen den abgeleiteten Typ in den Basisklassen in einem typischen CRTP -Anwendungsfall einfädeln, während gleichzeitig einen anderen Vorlagenparameter an die verschiedenen Basisklassen übergeben.

Das heißt, eine typische Basisklasse wird:

template <typename Derived, typename X, typename Y>
struct SomeBase {
};

Und Sie möchten Ihren Typ erstellen müssen, damit Sie die steuern können X und Y und gleichzeitig die komplette übergeben Derived Klasse.


Ich denke, ich würde das verwenden apply Trick, um die Basisklasse im laufenden Fliegen aus einem Adapter zu generieren Derived Klasse.

template <typename Derived, typename X, typename Y>
struct SomeBase {};

template <typename X, typename Y>
struct SomeBaseFactory {
  template <typename Derived>
  struct apply { typedef SomeBase<Derived, X, Y> type; };
};

// Generic application
template <typename Fac, typename Derived>
struct apply {
  typedef typename Fac::template apply<Derived>::type type;
};

Dann erstellen Sie den Typ als:

typedef MyFoo< SomeBaseFactory<int, float> > SuperFoo;

Wo Foo ist definiert als:

template <typename... Args>
struct Foo: apply<Args, Foo<Args...>>::type... {
};

Und nur weil es eine Weile her ist, seit ich so tief in Vorlagen gestapft habe, Ich habe es überprüft, es funktionierte.


Natürlich die Factory selbst ist für einen bestimmten Typ nicht wirklich spezifisch, sodass wir den Wrapper -Ansatz, den Sie experimentiert hatten, wiederverwenden können:

template <template <typename...> class M, typename... Args>
struct Factory {
  template <typename Derived>
  struct apply { typedef M<Derived, Args...> type; };
};

Und ja, Es funktioniert auch.

Andere Tipps

Wenn ich Ihre Frage korrekt verstehe, sollten Sie Vorlagen -Aliase erstellen, die jedes Mixin auf einen einzelnen Vorlageparameter reduzieren.

template <typename Derived>
using BarIntFloat = Bar<Derived, Int, Float>;

template <typename Derived>
using BazQux = Baz<Derived, Qux>;

typedef Foo<BarIntFloat, BazQux> MyFoo;

Hier ist eine Lösung, die ich mir ausgedacht habe. Es mag eine elegantere Möglichkeit geben, dies zu tun, aber ich könnte mir keine vorstellen. Eine Einschränkung ist, dass alle verwendeten Mixins zuerst in der verschachtelt werden müssen wrapper Struktur zusammen mit ihren jeweiligen Argumenten.

template <template <class...> class Mixin, class... Args>
struct wrapper
{
        typedef Mixin<Args...> type;
};

template <class... Args>
struct test
{

};

template <class Arg, class... Args>
struct test<Arg, Args...> : Arg::type, test<Args...>
{

};

template <class T>
class mixin1 {};

template <class T1, class T2>
class mixin2 {};

template <class T1, class T2, class T3>
class mixin3 {};

int main()
{
        test<wrapper<mixin1, int>, wrapper<mixin2, int, float>> foo;
        return 0;
}

@void-pointer

Dies ist eine grundlegende Auslassung von variadischen Vorlagen. Der Benutzer kann nicht von t ... oder i-te Wert aus Werten erhalten ...

Hier ist eine Verbindung Von Going Native 2012 Lecture von Andrei Alexandrescu:

template <typename... Ts>
void fun(const Ts&... vs) {}

• TS ist kein Typ; vs ist kein Wert!

typedef Ts MyList; // error!
Ts var; // error!
auto copy = vs; // error!

TS/VS sollte also eine Art Tupel sein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top