2016-08-04 16 views
-1

Entschuldigung für den verwirrenden Titel, da ich nicht sicher bin, wie man es formulieren soll. Was ich versuche zu tun, wird im Grunde zu einem Typ umgewandelt, der dynamisch von einer Karte abgerufen wird. (Die Karte wird keine Instanz haben, aber wird einen Typ haben, wenn das möglich ist)Ist es möglich, den Typ eines Objekts in einer Karte zu Castingzwecken zu speichern?

Erlauben Sie mir, mit einem Beispiel zu erklären. Angenommen, ich eine Basisklasse baseFoo

class baseFoo 
{ 
} 

und dann habe ich zwei verschiedene Klassen genannt haben, die von baseFoo erben derFooA und derFooB genannt

class derfooA : public baseFoo 
{ 
} 

und in ähnlicher Weise für derfooB

class derfooB : public baseFoo 
{ 
} 

Jetzt Ich wollte wissen, ob ich nur einen Typ in einer Map speichern kann (keine Instanz des Typs) - einfach ein Variable-Typ) so etwas wie dies

//STATEMENT A: 
std::map<std::string , baseFoo> myMap= {{"derfooA",derfooA}, {"derfooB", derfooB}}; 

Dann würde ich gerne so etwas wie dies tun:

sagen, ich habe eine baseFoo ptr und ich mag den ptr auf eine bestimmte Art gesenkten basierend auf ein Faden. Also könnte ich das tun:

Jetzt ist meine Frage, ob solch ein Mechanismus möglich ist, wie würde meine Aussage aussehen?

+0

Die 'derFooA' in der' dynamic_cast' Anweisung weist darauf hin, dass Sie den Zieltyp kennen, warum also in einer Karte nachschlagen? – aschepler

+3

Welches Problem versuchen Sie zu lösen? Warum brauchst du den Downcast? – Barry

+0

Ich versuche, zu einem bestimmten Typ zu werfen, würde dieser Typ aus einer Zeichenfolge ermittelt werden. Um dies zu erreichen, würde ich liek eine Zeichenkette auf einen Typ für diesen Zweck zuordnen Ich verwende eine Karte –

Antwort

2
template<class...Ts> 
struct types { using type=types; }; 

dies ist ein Bündel von Typen.

template<class T>struct tag_t{constexpr tag_t(){}; using type=T;}; 
template<class T>constexpr tag_t<T> tag{}; 

Dies ist ein Typ-Tag.

template<class T, class U> 
T* tag_dynamic_cast(tag_t<T>, U* u) { 
    return dynamic_cast<T*>(u); 
} 
template<class T, class U> 
T& tag_dynamic_cast(tag_t<T>, U& u) { 
    return dynamic_cast<T&>(u); 
} 

Damit können Sie einen dynamischen Cast basierend auf einem Tag versenden.

template<class F, class Sig> 
struct invoker; 
template<class F, class R, class...Args> 
struct invoker<F, R(Args...)> { 
    R(*)(void*, Args...) operator()() const { 
    return [](void* ptr, Args...args)->R { 
     return (*static_cast<F*>(ptr))(std::forward<Args>(args)...); 
    }; 
    } 
}; 
template<class F, class...Sigs> 
std::tuple<Sigs*...> invokers() { 
    return std::make_tuple(invoker<F, Sigs>{}()...); 
} 

so an diesem Punkt haben wir ein Tupel von Zeigern auf Funktionen, die ein bestimmtes Objekt F Typ mit einem Satz von Signaturen Sigs für jede Unterschrift aufrufen wird.

Wir würden nächster einen dipatcher schreiben, die die „richtigen“ Sigs von Sigs... basierend auf einigen Anruf, um es auf eine std::tuple von Sigs* mit einem void* ersten Argumente wählen würden.

Jetzt nehmen wir eine types<...> der Typen, die Sie zu Cast-to unterstützen möchten. Wir verwenden das, um eine Typ-Lösch-Klasse zu erzeugen, die einen übergebenen Lambda in einem std::unique_ptr<void, void(*)(void*)> speichert. Die Signaturen, die wir unterstützen, sind tag_t<x>, wobei x über die Typen in types<x...> variiert.

Dies ist Ihr dynamischer Dispatcher.

Wir sind fast den ganzen Weg dorthin. Als nächstes bauen wir etwas, das einen dynamischen Dispatcher und einen void* nimmt, und ruft es mit tag_t<x> auf. Es löscht die tag_t<x> es wird den dynamischen Dispatcher mit aufrufen, so dass die Schnittstelle es nicht verfügbar macht. Es ist im Grunde ein Binder zu einer Std-Funktion an diesem Punkt, einfach.

//STATEMENT A: 
std::map<std::string , helper<derFooA, derFooB>> myMap= 
    {{"derfooA",tag<derfooA>}, {"derfooB", tag<derfooB>}}; 
myMap[str]([&](auto&& tag) { 
    auto* dfoo = tag_dynamic_cast(tag, baseFoo_ptr); 
}); 

und während das Lambda wird für jeden abgeleiteten Typ, der nur eine instantiiert werden, die Lauf ist derjenige sein wird, in der Karte gespeicherten Wert übereinstimmt.

Sie werden feststellen, dass Sie innerhalb des Lambda gefangen sind. Ja. Sie können auch keine echten Informationen ausgeben, außer als Laufzeitstatus.

Jetzt sind Chancen Ihr wirkliches Problem hat eine einfachere Lösung. Aber das ist ein Fahrplan, wie es geht. Ich würde zu viel Zeit brauchen, um es selbst zu schreiben.

0

Speichern Sie die Art innerhalb der Instanz, etwa so:

class baseFoo 
{ 
public: 
class enum eClass 
{ 
    a, 
    b, 
} myType; 

baseFoo(eClass type) 
: myType(type) 
{} 
eClass getType() { return myTpe; }| 
}; 

class derfooA : public baseFoo 
{ 
public: 
    derfooA() 
    : baseFoo(baseFoo::eClass::a) 
    {} 
}; 

... 

baseFoo * ptr; 

... 

switch(ptr->getType()) { 
    case baseFoo::eClass::a: 
    ... do something