2016-09-26 2 views
3

Angenommen, wir haben eine Datenstruktur Foo, die eine Reihe von Elementen verwaltet. Es sollte möglich sein, Attribute den Elementen nach Bedarf zuzuordnen. Die Attribute sollten jeweils in einem separaten Vektor gespeichert werden. Wir setzen diese mittels variadische Vorlagen:Wie konvertiert man zwischen verschiedenen Instanziierungen derselben variadischen Vorlage?

#include <vector> 

template <typename ...Attrs> 
struct Foo : public Attrs... { 
    Foo(int n = 0) { 
    using PackExpansionT = int[]; 
    PackExpansionT{0, (Attrs::values.resize(n), 0)...}; 
    } 
}; 

struct AttrA { std::vector<int> values; }; 
struct AttrB { std::vector<float> values; }; 
struct AttrC { std::vector<double> values; }; 

int main() { 
    Foo<AttrA, AttrB> foo; // Maintains set of elements with two attributes each. 
}; 

Jetzt habe ich einen Konvertierungsoperator mit folgenden Semantik will:

Foo<AttrB, AttrC> bar = foo; // bar.AttrB::values should be a copy of foo.AttrB::values. 

Dies ist nur ein Beispiel. Im Allgemeinen sollte der Konvertierungsoperator ein Foo mit beliebigen Attributen in ein anderes Foo mit beliebigen Attributen konvertieren können. Attribute, die mit beiden Foo s verknüpft sind, sollten kopiert werden. Attribute, die nicht mit beiden verknüpft sind, können standardmäßig beibehalten werden. Ich habe jedoch keine Ahnung, wie ich es umsetzen soll.

template <typename ...OthersAttrs> 
    operator Foo<OthersAttrs...>() const { 
    // ...? 
    } 
+1

Was Sie über Attribute tun, die mit den zugehörigen das Ziel, aber nicht die Quelle? – merlin2011

+0

Nicht wichtig für jetzt. Vielleicht ist ihr Wert auf einen Standardwert eingestellt, vielleicht ist ihr Wert einfach undefiniert. – user1494080

+0

@ user1494080 Es ist ziemlich wichtig: Was soll 'bar' nach der Kopierinitialisierung von 'foo' sein? – Barry

Antwort

5

Wir können einfach eine Reihe unabhängiger Entscheidungen treffen. Lassen Sie uns zunächst einen Konstruktor hinzufügen, so dass wir Foo von seinem Attribut Bestandteile konstruieren kann:

Foo(Attrs const&... attrs) 
: Attrs(attrs)... 
{ } 

nächstes für jedes Attribut in Others, werden wir entweder niedergeschlagenen this in den entsprechenden Typ, wenn möglich, oder einen Standard konstruierten eine Rück ansonsten:

template <typename... Others> 
operator Foo<Others...>() const { 
    return {get_attr<Others>(this)...}; 
} 

wo:

template <class T> 
T const& get_attr(T const* v) const { 
    return *v; 
} 

template <class T> 
T get_attr(...) const { 
    return T{}; 
} 
2

den Umriss ich denken kann:

template <typename ...OthersAttrs> 
operator Foo<OthersAttrs...>() const 
{ 
    Foo<OthersAttrs...> rv(GetNSomehow()); 
    (int[]){(CopyAttr<Attrs>(&rv), 0)...}; 
    return rv; 
} 

template<typename Attr> 
void CopyAttr(Attr *rv) const // Overload A 
{ 
    rv->values = ((const Attr*)this)->values; 
} 

template<typename Attr> 
void CopyAttr(...) const // Overload B 
{ 

} 

Der Trick hier ist Attribut Attribut zu gehen. Wenn das Attribut rv das Attribut hat, wird die erste Überladung ausgewählt und kopiert.
Andernfalls würde die zweite Überladung gewählt werden, die nichts tun wird.

Verwandte Themen