2016-07-31 4 views
10

Ist es möglich, type_id (T) in C++ zu implementieren, die manuelle Typregistrierung noch RTTI nicht benötigen?Implementierung von type_id (T) in C++ ohne Typregistrierung oder RTTI

Alle Lösungen I (einschließlich boost :: typeindex) gesehen haben, sind auf Spezialisierung basiert und erfordern eine manuelle „Registrierung“ wie folgt aus:

class A { 
public: 
    BOOST_TYPE_INDEX_REGISTER_CLASS 
    virtual ~A(){} 
}; 

struct B: public A { 
    BOOST_TYPE_INDEX_REGISTER_CLASS 
}; 

Aber ich wünschte, Typ-ID in der Lage sein zu bekommen für Beliebiger Typ einschließlich Bibliothekstypen, die ich in meinem Code nicht neu definieren kann.

+0

Nicht sicher, wonach Sie fragen. ['typeid (T)'] (http://en.cppreference.com/w/cpp/language/typeid) benötigt RTTI nicht; Es ist zur Kompilierzeit aufgelöst. Nur 'typeid (Ausdruck) 'benötigt RTTI. – Oktalist

+0

Ich möchte beliebige Typen ohne RTTI identifizieren. Außerdem möchte ich weder die zu identifizierenden Typen ändern noch manuelle Aktionen für jeden dieser Typen durchführen. –

+0

Identifizieren auf welche Weise? Warum ist 'typeid' nicht ausreichend? – Oktalist

Antwort

14

Im Allgemeinen ist die Antwort "Nein". Sie können keine Fair-Type-ID ohne RTTI oder Spezialisierung implementieren.

Aber es gibt einen sehr starken Trick. Es ist nicht offensichtlich, daher ist es in der C++ Welt ungewöhnlich.

Jeder moderne Compiler C++ unterstützt so genannte Funktion Pretty-Print-Makro, , die Sie einzigartige Kennung einer Funktion mit der ganzen Art Parameter ausgepackt erhalten können.

So können Sie so etwas wie den folgenden Code verwenden:

#pragma once 

#undef UNIQUE_FUNCTION_ID 

#if defined(_MSC_VER) 
    #define UNIQUE_FUNCTION_ID __FUNCSIG__ 
#else  
    #if defined(__GNUG__) 
    #define UNIQUE_FUNCTION_ID __PRETTY_FUNCTION__ 
    #endif 
#endif 

template<typename T> 
class TypeId 
{ 
public: 
    static int typeId() 
    { 
     static int s_id = HASH(UNIQUE_FUNCTION_ID); 
     return s_id; 
    } 
}; 

Wo HASH Funktion jeder gute Hash sein, die Sie mögen.

Nachteile:

  1. Ihre binäre würde für jeden Typ durch lange char Konstanten verunreinigt werden Sie verwenden (aber in realen Anwendungen ist Overhead nicht so problematisch, wir diesen Ansatz verwendet haben sehr intensiv, ohne erhebliche Auswirkungen auf die Distro . Größe UPD: dies mit constexpr)
  2. Typ-IDs vermieden werden möglicherweise nicht erzeugt würde portable über Compiler, Compiler-Versionen noch einmal verschiedene Builds (oftenly es ist kein Problem)
  3. nicht der Compiler alle Unterstützung Makro mit semantischen erforderlich (MSVC, G ++ und Clang funktionieren wie ein Charme)
  4. Treats T und const T& als verschiedene Arten

Vorteile (aber es kann vor Hashing von UNIQUE_FUNCTION_ID mit zusätzlicher Verarbeitung festgelegt werden):

  1. Sehr einfach
  2. Erfordert nicht RTTI zu implementieren
  3. und unterstützt beliebigen Typ
  4. Arbeitet für ausführbare Dateien mit DLLs/SharedObjects/DyLibs
  5. Bleibt zwischen den Programmausführungen stabil
+0

Scheint vernünftig, danke! –

+1

Sie könnten vermeiden, die Binärdatei mit vielen 'char []' Konstanten zu verschmutzen, indem Sie 'HASH' constexpr machen. – Oktalist

+0

@Oktalist netter Hinweis! –

3

Normalerweise verwende ich Zeiger, um zu funktionieren. Da jede Instantiierung einer Template-Funktion eine andere Adresse hat, erhalte ich einen freien Hashing-Mechanismus, der vom Compiler implementiert wird.

Hier ist, wie ich es tun:

using type_id_t = void(*)(); 

template<typename> 
void type_id() {} 

Das ist alles!Jetzt können Sie es in Karten wie folgt verwenden:

std::map<type_id_t, std::string> myMap; 

myMap[type_id<int>] = "a int"; 
myMap[type_id<SomeType>] = "some type"; 
+0

Würde es zwischen DLLs und Shared Objects funktionieren? –

+0

Ich habe versucht mit GCC und kling auf Linux, es funktioniert genauso wie es soll! Ich habe es nicht mit msvc und DLLs getestet, aber es funktioniert sicher mit msvc und statische libs. –

+0

Ja, statische libs sollte kein Problem sein, aber ich bin ziemlich sicher, dass es einige Bedingungen gibt, wenn es im Falle von DLLs fehlschlagen kann. Auch ich denke, dass solche ID zwischen den Programmanforderungen ändern wird. Wie auch immer, es ist ein sehr schöner Trick. –

2

CRTP Idiom und ein C-ish Typen System kann in diesem Fall helfen:

#include<cstddef> 
#include<cassert> 

struct B { 
    static std::size_t cnt() noexcept { 
     static std::size_t val = 0; 
     return val++; 
    } 
}; 

template<typename T> 
struct I: private B { 
    static std::size_t type() noexcept { 
     static std::size_t t = B::cnt(); 
     return t; 
    } 
}; 

struct T: I<T> { }; 
struct S: I<S> { }; 

int main() { 
    assert(T::type() != S::type()); 

    T t1, t2; 
    S s; 

    assert(t1.type() == t2.type()); 
    assert(t1.type() != s.type()); 
} 

Sie einen Makro verwenden können, wie es auch folgt :

#define TypedStruct(C) struct C: I<C> 

// ... 

TypedStruct(T) { }; 
TypedStruct(S) { }; 

wie in den Kommentaren erwähnt, wenn Sie es mit Ihren Klassen nicht stören möchten, können Sie einen ähnlichen Ansatz verwenden, wie es folgt:

#include<cstddef> 
#include<cassert> 

struct B { 
    static std::size_t cnt() noexcept { 
     static std::size_t val = 0; 
     return val++; 
    } 
}; 

template<typename T> 
struct Type: private B { 
    static const std::size_t type; 
}; 

template<typename T> 
const std::size_t Type<T>::type = B::cnt(); 

struct T { }; 
struct S { }; 

int main() { 
    assert(Type<T>::type != Type<S>::type); 
} 

Wie Sie sehen können, S und T werden nicht von der Type Klasse betroffen.
Letztere kann jederzeit verwendet werden, um ihnen eine eindeutige Kennung zu geben.

+0

Dieser Ansatz ist sehr zerbrechlich und _erfordert_ einige manuelle Arbeit für jeden Typ, der 'type_id' haben soll. Die Frage war, wie man "type_id" bekommt, ohne Typen zu ändern. –

+0

@PavelS. Ok, lassen Sie mich weitere Details hinzufügen, um zu erklären, wie Sie es verwenden können, ohne Ihre Typen zu ändern. – skypjack

+0

@PavelS. Fertig, jetzt können Sie eine eindeutige Kennung erhalten, ohne Ihre Typen zu ändern. – skypjack

Verwandte Themen