Pregunta

después de responder este pregunta que estaba tratando de encontrar is_complete plantilla en la biblioteca Boost y me di cuenta de que no existe tal plantilla en Boost.TypeTraits.¿Por qué no existe tal plantilla en la biblioteca de Boost?¿Cómo debería verse?

//! Check whether type complete
template<typename T>
struct is_complete
{   
  static const bool value = ( sizeof(T) > 0 );
};

...

// so I could use it in such a way
BOOST_STATIC_ASSERT( boost::is_complete<T>::value );

El código anterior no es correcto porque es ilegal aplicarlo. sizeof a un tipo incompleto.¿Cuál será una buena solución? ¿Es posible aplicar SFINAE en este caso de alguna manera?


Bueno, este problema no podría resolverse en general sin violar el regla ODR, pero hay una plataforma específica solución lo cual funciona para mí.

¿Fue útil?

Solución

La respuesta dada por Alexey Malistov se puede usar en MSVC con una modificación menor:

namespace 
{
    template<class T, int discriminator>
    struct is_complete {  
      static T & getT();   
      static char (& pass(T))[2]; 
      static char pass(...);   
      static const bool value = sizeof(pass(getT()))==2;
    };
}
#define IS_COMPLETE(X) is_complete<X,__COUNTER__>::value

Desafortunadamente, la macro predefinida COUNTER no es parte del estándar, por lo que no funcionaría en todos los compiladores.

Otros consejos

template<class T>
struct is_complete {
    static T & getT();
    static char (& pass(T))[2];
    static char pass(...);

    static const bool value = sizeof(pass(getT()))==2;
};

Puede que sea un poco tarde, pero hasta ahora, ninguna solución de C ++ 11 funcionó tanto para tipos completos como abstractos.

Entonces, aquí estás.

Con VS2015 (v140), g ++ > = 4.8.1, clang > = 3.4, esto está funcionando:

template <class T, class = void>
struct IsComplete : std::false_type
{};

template <class T>
struct IsComplete< T, decltype(void(sizeof(T))) > : std::true_type
{};

Gracias a Bat-Ulzii Luvsanbat: https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update -1 /

Con VS2013 (V120):

namespace Details
{

    template <class T>
    struct IsComplete
    {
        typedef char no;
        struct yes { char dummy[2]; };

        template <class U, class = decltype(sizeof(std::declval< U >())) >
        static yes check(U*);

        template <class U>
        static no check(...);

        static const bool value = sizeof(check< T >(nullptr)) == sizeof(yes);
    };

} // namespace Details


template <class T>
struct IsComplete : std::integral_constant< bool, Details::IsComplete< T >::value >
{};

Este está inspirado en Internet y afirmación estática que ¿El nombre de tipo de plantilla T no está completo?

Me temo que no puede implementar tales rasgos de tipo is_complete. La implementación dada por @Alexey no se compila en G ++ 4.4.2 y G ++ 4.5.0:

  

error: inicializando el argumento 1 de & # 8216; static char (& amp; is_complete :: pass (T)) [2] [with T = Foo] & # 8217;

En mi Mac, con G ++ 4.0.1 evaluar is_complete<Foo>::value donde struct Foo; está incompleto produce true que es aún peor que un error del compilador.

T puede estar completo e incompleto en el mismo programa, dependiendo de la unidad de traducción, pero siempre es del mismo tipo. Como consecuencia, como se comentó anteriormente, is_complete<T> también es siempre del mismo tipo.

Entonces, si respeta la ODR no es posible tener __COUNTER__ evaluando a diferentes valores dependiendo de dónde se usa; de lo contrario, significaría que tiene diferentes definiciones para is_complete<T, int> qué ODR prohíbe.

EDITAR: Como respuesta aceptada, yo mismo pirateé una solución que usa la macro IS_COMPLETE para crear una instancia de un tipo <=> diferente cada vez que se usa la macro <=>. Sin embargo, con gcc, no pude lograr que SFINAE funcionara en primer lugar.

Resolver esto requiere realizar el cálculo en el argumento predeterminado de la plantilla de rasgo, ya que intentar cambiar la definición de una plantilla viola la regla ODR (aunque una combinación de __COUNTER__ y namespace {} puede evitar la ODR).

Está escrito en C++ 11, pero se puede ajustar para que funcione en modo C++ 03 de un compilador moderadamente reciente compatible con C++ 11.

template< typename t >
typename std::enable_if< sizeof (t), std::true_type >::type
is_complete_fn( t * );

std::false_type is_complete_fn( ... );

template< typename t, bool value = decltype( is_complete_fn( (t *) nullptr ) )::value >
struct is_complete : std::integral_constant< bool, value > {};

Demostración en línea.

El argumento predeterminado se evalúa donde se nombra la plantilla, por lo que puede cambiar contextualmente entre diferentes definiciones.No es necesaria una especialización y definición diferente para cada uso;solo necesitas uno para true y uno para false.

La regla se proporciona en §8.3.6/9, que se aplica igualmente a los argumentos predeterminados de la función y a los argumentos de la plantilla predeterminada:

Los argumentos predeterminados se evalúan cada vez que se llama a la función.

Pero tenga cuidado, es casi seguro que usar esto dentro de una plantilla violará el ODR.Una plantilla creada en un tipo incompleto no debe hacer nada diferente que si se creara en un tipo completo.Personalmente solo quiero esto por un static_assert.

Por cierto, este principio también puede resultar útil si desea ir por el otro lado y implementar la funcionalidad de __COUNTER__ usando plantillas y sobrecargando.

Simplemente sonando para indicar que una respuesta (no dada por mí) a una pregunta no relacionada da una solución para la plantilla is_complete<T>.

La respuesta es aquí . No lo pego a continuación para no obtener crédito por error.

No puedo encontrar nada en el estándar que garantice que sizeof en un tipo incompleto producirá 0. Sin embargo, sí requiere que si T está incompleto en algún momento, pero se completa más adelante en esa unidad de traducción, que todas las referencias to T se refiere al mismo tipo, así que mientras lo leo, incluso si T está incompleto donde se invocó su plantilla, sería necesario decir que estaba completo si T se completa en algún lugar de esa unidad de traducción.

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