Pregunta

Tenemos un sub-proyecto "commonUtils' que tiene el número de código genérico-fragmentos utilizada en el proyecto principal.Una de esas cosas interesantes que vi fue :-

/*********************************************************************
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; 
}

Yo creí que el comentario y la idea de que es muy interesante plantilla, que aunque no es se utilizan en todo el proyecto.He intentado utilizar como esto sólo por curiosidad ...

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";

Pero ninguno de los que alguna vez devuelve true.MSVC de 2005, no da ninguna advertencia, pero Comeau advierte typeid expresión no tiene ningún efecto.Sección 5.2.8 en el estándar de C++ no dice nada parecido a lo que el comentario dice: es decir,typeid es se evalúa en tiempo de compilación para no polimórficas y tipos en tiempo de ejecución para polimórficos tipos.

1) Así que supongo que el comentario es engañosa/plain-mal o desde que el autor de este código es bastante senior programador de C++, que me estoy perdiendo algo?

2) OTOH, me pregunto si podemos probar si una clase es polimórfica(tiene al menos una función virtual) uso de alguna técnica?

3) Cuando uno quiere saber si una clase es polimórfica?Conjetura;para obtener la puesta en discurso de una clase mediante el uso de dynamic_cast<void*>(T) (como dynamic_cast sólo funciona en polimórficos clases).

A la espera de sus opiniones.

Gracias de antemano,

¿Fue útil?

Solución

No me puedo imaginar cómo cualquier manera posible que typeid se podría utilizar para comprobar que el tipo es polimórfico. Ni siquiera puede ser utilizado para afirmar que se trata, ya que typeid funcionará en cualquier tipo. Boost tiene una implementación aquí . En cuanto a por qué podría ser necesario - un caso que conozco es la biblioteca Boost.Serialization. Si va a guardar tipo no polimórfica, a continuación, puedes guardarlo. Si el ahorro de un polimorfo, usted tiene que recibe su tipo dinámico utilizando typeid, y luego invocar el método de serialización para ese tipo (mirando hacia arriba en alguna tabla).

Actualizar : parece que estoy realmente mal. Considere esta variante:

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

Esto funciona realmente como su nombre indica, precisamente por comentario en su fragmento de código original. La expresión dentro de typeid no se evalúa si "no designa un lvalue de tipo de clase polimórfica" (std 3.2 / 2). Así, en el caso anterior, si T no es polimórfico, no se evalúa la expresión typeid. Si T es polimórfico, a continuación, * t es de hecho lvalue de tipo polimórfico, de manera que toda la expresión tiene que ser evaluado.

Ahora, su ejemplo original todavía está mal :-). Se utiliza T(), no *t. Y T() crear rvalue (std 3.10 / 6). Por lo tanto, todavía se obtiene una expresión que no es "lvalue de clase polimórfica".

Eso es truco bastante interesante. Por otro lado, su valor práctico es algo limitada - porque mientras impulso :: is_polymorphic le da una constante de tiempo de compilación, éste le da un valor de tiempo de ejecución, por lo que no puede crear una instancia de código diferente para los tipos polimórficos y no polimórficos .

Otros consejos



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;
}

Desde C ++ 11, este está ahora disponible en la cabecera <type_traits> como std::is_polymorphic. Se puede utilizar como esto:

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";

Esto imprime simplemente "polybase = polimórficos".

Uno puede utilizar los hechos de que:

  1. dynamic_cast produce un error en tiempo de compilación si el argumento no es un polimórficos de la clase.De modo que puede ser utilizado con SFINAE.
  2. dynamic_cast<void*> es un válidos emitidos que devuelve la dirección de la completa polymorpic objeto.

Por lo tanto, en 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.
}

Estoy un poco confundido aquí, y espero conseguir algunos comentarios sobre esta respuesta explicando lo que me falta.

Sin duda, si desea averiguar si una clase es polimórfico, todo lo que tiene que hacer es preguntar si admite dynamic_cast, ¿no es así?

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*> {};

¿Puede alguien señalar una falla en esta aplicación? Me imagino que debe haber una, o debe haber sido uno en algún momento en el pasado, porque la documentación Boost continúa afirmando que is_polymorphic "no puede ser implementado de forma portátil en el lenguaje C ++".

Sin embargo, "portable" es una especie de palabra equívoca, ¿verdad? Tal vez sólo están aludiendo a la forma en MSVC no admite la expresión SFINAE, o algunos dialectos como C ++ Embedded no apoyar dynamic_cast. Tal vez cuando dicen "++ lenguaje de C" que significan "un mínimo común denominador subconjunto del lenguaje C ++." Pero tengo una persistente sospecha de que tal vez quieren decir lo que dicen, y soy al que le falta algo.

El enfoque typeid en el PO (modificada por una respuesta posterior para utilizar no un lvalue un valor p) también parece estar bien, pero por supuesto que no es constexpr y requiere la construcción de una realidad T, que puede ser muy cara. Así que este enfoque dynamic_cast parece mejor ... a menos que no funciona por alguna razón. Pensamientos?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top