Si le pedimos al compilador que nos diga algo acerca de un tipo de clase T
que no ha sido declarado , tendremos que obtener un error de compilación. No hay manera de que redondee eso. Por lo tanto, si queremos saber si la clase T
"existe", donde T
podría ni siquiera han sido declarados sin embargo, debemos declarar T
primero.
Pero eso está bien, porque la simple declaración T
no hará que "existe", ya que lo que debemos entender por T
existe es T
se define. Y si, después de haber declarado T
, , puede determinar si ya está definido, no necesita estar en confusión.
El problema es determinar si T es un tipo de clase definido.
sizeof(T)
hay ayuda aquí. Si T
no está definido, dará un error incomplete type T
. Del mismo modo typeid(T)
. Tampoco es ninguna buena la elaboración de una sonda SFINAE del tipo T *
, porque T *
es es un tipo definido , siempre y cuando T
ha sido declarado, incluso si no es T
. Y ya que estamos obligados a tener una declaración de clase T
, std::is_class<T>
no es el respuesta tampoco, debido a que la declaración será suficiente para que diga "Sí".
C++ 11 proporciona std::is_constructible<T ...Args>
en <type_traits>
.¿Puede ofrecer una solución off-the-peg? - dado que si se define T
, entonces debe tener al menos un constructor.
No estoy seguro. Si conoce la firma de al menos un constructor público de T
, entonces el <type_traits>
de GCC (a partir de 4.6.3) efectivamente hará el negocio. Digamos que un constructor público conocido es T::T(int)
. Entonces:
std::is_constructible<T,int>::value
será cierto si se ha definido T
y falso si T
se limitó a declarar.
Pero esto no es portátil. <type_traits>
en VC++ 2010 no proporciona todavía std::is_constructible
e incluso su std::has_trivial_constructor<T>
se vomitar si T
no está definido: std::is_constructible
más probable cuando no llegan va a seguir su ejemplo. Además, en la eventualidad de que solo existan constructores privados de de T
para ofrecer std::is_constructible
, incluso GCC barf (que levanta la ceja).
Si se define T
, debe tener un destructor , y solo un destructor. Y ese destructor es más probable que sea público que cualquier otro miembro posible de T
. En esa luz, el juego más simple y más fuerte que podemos hacer es crear una sonda SFINAE para la existencia de T::~T
. sonda
Este SFINAE no puede ser elaborado en la forma de rutina para determinar si T
tiene una función miembro ordinario mf
- haciendo que el "Sí sobrecarga" de la función de la sonda SFINAE tener un argumento que se define en términos de la tipo de &T::mf
. Porque no podemos tomar la dirección de un destructor (o constructor).
Sin embargo, si se define T
, entonces T::~T
tiene un tipo DT
- que debe ser cedido por decltype(dt)
siempre dt
es una expresión que se evalúa como un invocación de T::~T
; y por lo tanto, DT *
también será un tipo que, en el principio , se puede dar como el tipo de argumento de una sobrecarga de función. Por lo tanto, podemos escribir la sonda como esta (GCC 4.6.3):
#ifndef HAS_DESTRUCTOR_H
#define HAS_DESTRUCTOR_H
#include <type_traits>
/*! The template `has_destructor<T>` exports a
boolean constant `value that is true iff `T` has
a public destructor.
N.B. A compile error will occur if T has non-public destructor.
*/
template< typename T>
struct has_destructor
{
/* Has destructor :) */
template <typename A>
static std::true_type test(decltype(std::declval<A>().~A()) *) {
return std::true_type();
}
/* Has no destructor :(*/
template<typename A>
static std::false_type test(...) {
return std::false_type();
}
/* This will be either `std::true_type` or `std::false_type` */
typedef decltype(test<T>(0)) type;
static const bool value = type::value; /* Which is it? */
};
#endif // EOF
sólo con la restricción de que T
debe tener un destructor pública ser legalmente invocado en la expresión argumento de decltype(std::declval<A>().~A())
. (has_destructor<T>
es una adaptación simplificada de la plantilla método de introspección contribuí here.)
El significado de esa expresión argumento std::declval<A>().~A()
puede ser oscuro para algunos, específicamente std::declval<A>()
.La plantilla de función std::declval<T>()
se define en <type_traits>
y devuelve un T&&
(rvalue-referencia a T
) - aunque sólo podrá ser invocado sin evaluar contextos, como el argumento de decltype
. Por lo tanto, el significado de std::declval<A>().~A()
es una llamada al ~A()
sobre un determinado A
. std::declval<A>()
nos sirve bien aquí al obviar la necesidad de que haya cualquier constructor público de T
, o para que lo sepamos.
En consecuencia, el tipo de argumento de la sonda SFINAE para el "Sí sobrecarga" es: puntero al tipo de destructor de A
y test<T>(0)
coincidirá que sobrecarga por si acaso hay un tipo tal como destructor de A
, por A
= T
con has_destructor<T>
en la mano - y su limitación a destructibles valores de T
firmemente en la mente del público - se puede comprobar si una clase es T
definido en algún punto en su código, asegurándose de que declare antes de hacer una pregunta al . Aquí hay un programa de prueba.
#include "has_destructor.h"
#include <iostream>
class bar {}; // Defined
template<
class CharT,
class Traits
> class basic_iostream; //Defined
template<typename T>
struct vector; //Undefined
class foo; // Undefined
int main()
{
std::cout << has_destructor<bar>::value << std::endl;
std::cout << has_destructor<std::basic_iostream<char>>::value
<< std::endl;
std::cout << has_destructor<foo>::value << std::endl;
std::cout << has_destructor<vector<int>>::value << std::endl;
std::cout << has_destructor<int>::value << std::endl;
std::count << std::has_trivial_destructor<int>::value << std::endl;
return 0;
}
construido con GCC 4.6.3, esto le indicará que los 2 // Defined
clases tienen destructores y las clases 2 // Undefined
no lo hacen. La quinta línea de salida dirá que int
es destructible, y la línea final mostrará que std::has_trivial_destructor<int>
está de acuerdo. Si queremos para restringir el campo a los tipos de clases, std::is_class<T>
se puede aplicar después de determinamos que T
es destructible.
Visual C++ 2010 no proporciona std::declval()
. Para apoyar ese compilador puede agregar lo siguiente en la parte superior de has_destructor.h
:
#ifdef _MSC_VER
namespace std {
template <typename T>
typename add_rvalue_reference<T>::type declval();
}
#endif
Quiere decir si una clase contiene una clase particular ¿Educación física? O si existe un tipo en un ámbito de espacio de nombres? (No veo cómo esto último sería útil) – sbabbi
El compilador hará eso por usted. Por favor, explica lo que quieres hacer? –
Para aclarar: ¿la clase es solo un identificador de código fijo, por lo que no depende de la sustitución de ningún parámetro de plantilla? – ndkrempel