teorico programas practico paso funciones ejemplos codigos clases caracteristicas c++ c++11 final template-meta-programming sfinae

programas - Comprobación de la existencia de la función miembro de C++, posiblemente protegida



ejemplos de programas en c++ pdf (3)

He puesto algunas ideas sobre cómo implementar las cosas que solicitó y llegué a una conclusión totalmente diferente.

El problema que nos ocupa es muy interesante: ¿cómo puedo verificar si una clase implementa una interfaz oculta? Lamentablemente, el problema es una contradicción con el principio de sustitución de liskov; uno de los principios básicos orientados a objetos.

Esto se debe en parte a la estructura de tipos de std::shared_ptr . shared_ptr no refleja la relación de herencia de sus tipos de argumentos. Dada una clase T y una clase U , donde la class T : public U {}; contiene shared_ptr<T> : public shared_ptr<U> {}; no !

Su implementación tiene un defecto fundamental en el nivel de interfaz. Si está buscando tiempo de compilación, si existe una función y luego extrae el tipo, solo podrá deserializar las estructuras de datos que utilizan punteros compartidos.

Además, si std::shared_ptr queda obsoleto o si desea utilizar algún otro medio para adquirir memoria ( std::allocator interface? Alguna asignación de región / grupo) tendrá que adaptar sus interfaces.

Mi opinión personal es crear algún tipo de interfaz de fábrica y registrarla en algún lugar del deserializador.

El segundo sería tener una clase de fábrica que exponga una interfaz de plantilla implícita (y usar CRTP para especializar la interfaz a las necesidades de los usuarios, es decir:

template <class ActualType, class IfType=ActualType, class Allocator=default::allocator<ActualType>> class Deserializable { static IfType alloc(ActualType &&t) { Allocator a; // choose another interface as your please. return a.allocate(t); /* implement me */ } private: }; class MyClass : public InterfaceClass, public Deserializable<MyClass,InterfaceClass> { /* your stuff here */ };

  • Esto le da una cantidad razonable de abstracción en sus clases de plantilla.
  • El usuario de su biblioteca sabe lo que quiere a cambio de todos modos. y si elige asignar algo más que std::shared_ptr , podría hacerlo (creando su propio Allocator )
  • El usuario no tiene que implementar nada más que especificar tipos (y realmente se los pasa a usted, así que no hay segundos intentos).

Podría interpretar esto como una clase de política (no en el sentido estricto de Andrei Alexandrescu). La biblioteca de serialización exige una política de asignación. El usuario puede decidir cómo se implementa esta política. En este caso, una opción sobre cómo asignar el objeto deserializado y el tipo , que podría ser diferente. Debido a que el Allocator tiene una implementación predeterminada y es un argumento de plantilla, otra opción se le pasa al usuario si así lo desea.

Para comprender el poder de este enfoque, le doy la bienvenida para que observe el código del boost::operator que utiliza esta técnica para especificar el tipo de retorno y los argumentos de los operadores aritméticos en tiempo de compilación.

Nota

Para las personas que también busquen en esta publicación las respuestas del problema original, les sugiero que utilicen este enfoque . Sin embargo, requiere que el miembro sea público, ya que busca un puntero de función miembro de un nombre de pila.

Estoy tratando de detectar si una clase tiene una función particular (específicamente shared_from_this() , que se hereda de std::enable_shared_from_this<Some Unknown Class> ). Para hacer las cosas más complicadas, necesito saber si tiene esta función incluso si ha sido heredada de una clase base distante o heredada usando acceso protegido.

He analizado otras preguntas como esta , pero los métodos suministrados no funcionan para detectar funciones de miembro protegidas.

El método actual que estoy usando es el siguiente:

template <class T> struct shared_from_this_wrapper : public T { template <class U> static auto check( U const & t ) -> decltype( t.shared_from_this(), std::true_type() ); static auto check( ... ) -> decltype( std::false_type() ); }; template<class T> struct has_shared_from_this : decltype(shared_from_this_wrapper<T>::check(std::declval<shared_from_this_wrapper<T>>())) { };

El error en mi solución actual es que no funciona con clases declaradas final . Así que estoy buscando una solución para probar una función miembro que satisfaga:

  1. Trabaja con clases declaradas final
  2. Funciona con funciones miembro protegidas
  3. Trabaja con herencia
  4. No necesita saber el tipo de devolución de la función
  5. Compila en gcc, clang y MSVC 2013 (el último que potencialmente limita demasiado a SFINAE)

Editar: Tengo una solución potencial que funciona pero que requiere ser amiga de una clase auxiliar, que tampoco es una solución ideal, pero posiblemente una solución temporal por ahora (ya que cumple todos los requisitos):

struct access { template <class T> static auto shared_from_this( T const & t ) -> decltype( t.shared_from_this() ); }; template <class U> static auto check( U const & t ) -> decltype( access::shared_from_this(t), std::true_type() ); static auto check( ... ) -> decltype( std::false_type() ); template<class T> struct has_shared_from_this2 : decltype(check(std::declval<T>())) { }; struct A : std::enable_shared_from_this<A> {}; struct B : protected A { friend class access; };

Otra edición: ejemplos de clases y qué tipo de rasgo debe verificar la existencia de algo así como shared_from_this :

struct A : std::enable_shared_from_this<A> {}; // should return true struct B final : protected A {}; // should return true struct C : A {}; // should return true struct D {}; // should return false

Debo mencionar que mi objetivo final en la detección de si esta función existe es determinar el tipo de retorno de la misma para averiguar el tipo en el que std::enable_shared_from_this se std::enable_shared_from_this . Heredar de std::enable_shared_from_this<T> le da std::shared_ptr<T> shared_from_this() , y T es en última instancia lo que necesito averiguar. Esto es necesario para una serialización adecuada de los tipos que heredan de std::enable_shared_from_this .

Editar parte 3: La edición:

Esto se está haciendo para el cereal biblioteca de serialización y, como tal, no tengo control sobre cómo un usuario quiere diseñar su clase. Me gustaría poder serializar cualquier tipo de usuario que derive de std::enable_shared_from_this , que incluye usuarios que declaran sus clases como finales o usan herencia protegida en algún momento. Cualquier solución que requiera intromisión con el tipo real que se verifica no es una solución válida.


Me voy a tomar la libertad de cuestionar la pregunta. No todos los objetos pasados ​​a través de shared_ptr heredan de enable_shared_from_this.

Quizás esto sea lo que estás buscando o dar algunas ideas adicionales:

class Foo1 { }; class Foo2 : public std::enable_shared_from_this< Foo2 > {}; class Foo3 final : protected Foo2 {}; struct Serialize { template <typename T> void write( T* ) { printf( "not shared!/n" ); } template <typename T> void write( std::shared_ptr<T> ) { printf( "shared!/n" ); } }; int test( ) { typedef std::shared_ptr<Foo2> Foo2Ptr; typedef std::shared_ptr<Foo3> Foo3Ptr; Serialize s; Foo1* pFoo1 = nullptr; Foo2Ptr pFoo2; Foo3Ptr pFoo3; s.write( pFoo1 ); s.write( pFoo2 ); s.write( pFoo3 ); return 0; }

En tiempo de ejecución, la salida es:

not shared! shared! shared!


Si el único objetivo es detectar el tipo T, entonces sugiero que le guste en el STL y agregue un typedef:

template <class T> struct enable_shared_from_this : public T { typedef T base_type; // ... };

Entonces puedes usarlo así:

class A : enable_shared_from_this<B> { } A::base_type // == B

Este ejemplo asume que usted sabe que A hereda de shared_from_this_wrapper .