Frage

Wir haben ein Teilprojekt ‚commonUtils‘, die über das übergeordnete Projekt verwendet, um vielen generischen Code-Schnipsel hat. Eine solche interessanten Sachen, die ich sah, war: -

/*********************************************************************
If T is polymorphic, the compiler is required to evaluate the typeid 
stuff at runtime, and answer will be true.  If T is non-polymorphic, 
the compiler is required to evaluate the typeid stuff at compile time, 
whence answer will remain false
*********************************************************************/
template <class T> 
bool isPolymorphic() { 
   bool answer=false; 
   typeid(answer=true,T()); 
   return answer; 
}

glaubte ich, den Kommentar und dachte, dass es eine sehr interessante Vorlage ist, obwohl es nicht ist über das Projekt verwendet. Ich habe versucht, es so einfach aus Neugier mit ...

class PolyBase {
public:
   virtual ~PolyBase(){}
};

class NPolyBase {
public:
   ~NPolyBase(){}
};


if (isPolymorphic<PolyBase>())
  std::cout<<"PolyBase = Polymorphic\n";
if (isPolymorphic<NPolyBase>())
  std::cout<<"NPolyBase = Also Polymorphic\n";

Aber keiner von denen immer wieder wahr. MSVC 2005 gibt keine Warnungen aber Comeau warnt typeid Ausdruck hat keine Wirkung. Abschnitt 5.2.8 in der C ++ Standard sagt nichts wie das, was der Kommentar sagt das heißt typeid ist für Nicht-polymorphe Typen bei der Kompilierung ausgewertet und zur Laufzeit für polymorphe Typen.

1) Also ich denke, der Kommentar ist irreführend / plain-falsch oder seit dem Autor dieses Codes ist ein ganz Senior C ++ Programmierer, bin ich etwas fehlt?

2) OTOH, ich frage mich, ob wir, ob eine Klasse (zumindest eine virtuelle Funktion) mit einem gewissen Technik polymorpher testen können, ist?

3) Wenn würde man wissen will, ob eine Klasse polymorph ist? Wilde Vermutung; die Startadresse einer Klasse zu erhalten, indem dynamic_cast<void*>(T) mit (als dynamic_cast nur auf polymorphe Klassen arbeitet).

In Erwartung Ihrer Meinung.

Vielen Dank im Voraus,

War es hilfreich?

Lösung

Ich kann nicht jede mögliche Art und Weise vorstellen, wie das typeid verwendet werden könnte, dass Art ist polymorph zu überprüfen. Es kann nicht verwendet werden, selbst zu behaupten, dass es, da typeid auf jeder Art arbeiten. Boost hat eine Implementierung hier . Was, warum es notwendig sein könnte - ein Fall, den ich weiß, ist die Boost.Serialization Bibliothek. Wenn Sie nicht-polymorphen Typ speichern, dann können Sie einfach speichern. Wenn polymorphen eine Einsparung, haben Sie seine dynamische Art mit typeid zu bekommt, und dann Serialisierungsmethode für diese Art aufrufen (suchen sie in irgendeiner Tabelle oben).

Aktualisieren : es scheint, ich tatsächlich falsch bin. Betrachten Sie diese Variante:

template <class T> 
bool isPolymorphic() { 
    bool answer=false;
    T *t = new T();
    typeid(answer=true,*t); 
    delete t;
    return answer; 
}

Das tatsächlich funktioniert wie Name schon sagt, genau pro Kommentar in Ihrem ursprünglichen Code-Schnipsel. Der Ausdruck in typeid wird nicht ausgewertet, wenn es (std 3.2 / 2) „nicht ein L-Wert von polymorphen Klassentyp bezeichnen“. Also, oben in dem Fall, wenn T nicht polymorph ist, wird der typeid Ausdruck nicht ausgewertet. Wenn T polymorph ist, dann * t ist in der Tat lvalue polymorphen Typs, so gesamter Ausdruck muss ausgewertet werden.

Nun, Ihr ursprüngliches Beispiel ist immer noch falsch :-). Es verwendet T(), nicht *t. Und T() erstellen rvalue (std 3.10 / 6). So ergibt es noch einen Ausdruck, der nicht „L-Wert von polymorpher Klasse“ ist.

Das ist ziemlich interessant Trick. Auf der anderen Seite, ist seine praktische Wert etwas begrenzt - denn während boost :: Is_polymorphic Sie einen Compiler-Konstante gibt, dieses Sie einen Laufzeitwert gibt, so dass Sie nicht anderen Code für polymorphe und nicht-polymorphe Typen instanziieren .

Andere Tipps



class PolyBase {
public:   
    virtual ~PolyBase(){}
};

class NPolyBase {
public:
    ~NPolyBase(){}
};

template<class T>
struct IsPolymorphic
{
    struct Derived : T {
        virtual ~Derived();
    };
    enum  { value = sizeof(Derived)==sizeof(T) };
};


void ff()
{
    std::cout << IsPolymorphic<PolyBase >::value << std::endl;
    std::cout << IsPolymorphic<NPolyBase>::value << std::endl;
}

Da C ++ 11, ist dies nun in dem <type_traits> Header als std::is_polymorphic verfügbar. Es kann wie folgt verwendet werden:

struct PolyBase {
  virtual ~PolyBase() {}
};

struct NPolyBase { 
  ~NPolyBase() {}
};

if (std::is_polymorphic<PolyBase>::value)
  std::cout << "PolyBase = Polymorphic\n";
if (std::is_polymorphic<NPolyBase>::value)
  std::cout << "NPolyBase = Also Polymorphic\n";

Diese Drucke nur "polybasisch = Polymorphe".

Man kann verwenden, um die Tatsachen, dass:

  1. dynamic_cast versagt bei der Kompilierung, wenn das Argument nicht eine polymorphe Klasse. So dass es mit SFINAE verwendet werden.
  2. dynamic_cast<void*> ist eine gültige Besetzung, die die Adresse des vollständig polymorpic Objekt zurückgibt.

Daher wird in C ++ 11:

#include <iostream>
#include <type_traits>

template<class T>
auto is_polymorphic2_test(T* p) -> decltype(dynamic_cast<void*>(p), std::true_type{});

template<class T>
auto is_polymorphic2_test(...) -> std::false_type;

template<class T>
using is_polymorphic2 = decltype(is_polymorphic2_test<T>(static_cast<T*>(0)));

struct A {};
struct B { virtual ~B(); };

int main() {
    std::cout << is_polymorphic2<A>::value << '\n'; // Outputs 0.
    std::cout << is_polymorphic2<B>::value << '\n'; // Outputs 1.
}

Ich bin ein wenig verwirrt hier, und bin die Hoffnung, einige Kommentare zu dieser Antwort bekommen zu erklären, was ich fehle.

Sicher, wenn Sie möchten, um herauszufinden, ob eine Klasse polymorph ist, alles, was Sie tun müssen, ist fragen, ob es dynamic_cast unterstützt, nicht wahr?

template<class T, class> struct is_polymorphic_impl   : false_type {};
template<class T> struct is_polymorphic_impl
    <T, decltype(dynamic_cast<void*>(declval<T*>()))> : true_type {};

template<class T> struct is_polymorphic :
    is_polymorphic_impl<remove_cv_t<T>, void*> {};

Kann mir jemand einen Fehler in dieser Implementierung hinweisen? Ich stelle mir vor es sein muss, oder muss in der Vergangenheit ein zu einem bestimmten Zeitpunkt gewesen sein, denn die Boost-Dokumentation weiterhin, dass is_polymorphic Anspruch "nicht portabel in der Programmiersprache C ++ implementiert werden".

Aber „portabel“ ist eine Art eines Wiesel Wortes, nicht wahr? Vielleicht anspielend sie nur, wie MSVC nicht Ausdruck-SFINAE oder einige Dialekte wie Embedded C ++ unterstützen dynamic_cast nicht unterstützen. Vielleicht, wenn sie „die Sprache C ++“ bedeuten sie sagen, „ein kleinsten gemeinsamen Nenner Teilmenge der Programmiersprache C ++.“ Aber ich habe eine nagende Verdacht, dass sie vielleicht meinen, was sie sagen, und Ich bin derjenige, der etwas vermisst.

Der typeid Ansatz im OP (wie durch eine spätere Antwort geändert einen L-Wert nicht ein R-Wert verwenden) scheint auch in Ordnung, aber natürlich ist es nicht constexpr und es erfordert die Konstruktion tatsächlich einen T, die super teuer sein könnte. Also dieser dynamic_cast Ansatz scheint besser ... es sei denn, es aus irgendeinem Grund nicht funktioniert. Gedanken?

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