Pergunta

Depois de responder esta questão eu estava tentando encontrar o modelo is_complete na biblioteca Boost e percebi que não existe tal modelo no Boost.TypeTraits. Por que não existe tal modelo na biblioteca de impulso? Como ele deve ser parecido?

//! 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 );

O código acima não é correto, porque é ilegal para aplicar sizeof para um tipo incompleto. O que vai ser uma boa solução? É possível aplicar SFINAE, neste caso, de alguma forma?


Bem, este problema não pode ser resolvido, em geral, sem violar a ODR regra , mas não há uma plataforma específica solução que funciona para mim .

Foi útil?

Solução

A resposta dada por Alexey Malistov pode ser usado em MSVC com uma pequena modificação:

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

Infelizmente, o COUNTER macro predefinida não é parte do padrão, por isso não iria funcionar em cada compilador.

Outras dicas

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

Pode ser um pouco tarde, mas até agora, nenhum C ++ 11 solução funcionou para ambos os tipos completos e abstratas.

Então, você está aqui.

Com VS2015 (V140), g ++> = 4.8.1, tinido> = 3,4, este está a funcionar:

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

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

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

Com 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 é inspirado das internets e estática afirmam que template typename T não está completa?

Eu tenho medo que você não pode aplicar esse tipo is_complete traços. A implementação dada pelo @Alexey não consegue compilar em G ++ 4.4.2 e G ++ 4.5.0:

erro: inicializar argumento 1 de ‘static char (& is_complete :: pass (T)) [2] [com T = Foo]’

No meu Mac, com G ++ 4.0.1 avaliar is_complete<Foo>::value onde struct Foo; é yields incompletas para true que é ainda pior do que um erro do compilador.

T pode ser tanto completo e incompleto no mesmo programa, dependendo da unidade de tradução, mas é sempre o mesmo tipo. Como consequência, como comentado acima, is_complete<T> é sempre do mesmo tipo bem.

Então, se você respeitar ODR não é possível ter is_complete<T> avaliar a valores diferentes dependendo de onde ele é usado; caso contrário, isso significaria que você tem definições diferentes para is_complete<T> que proíbe ODR.

EDIT: Como a resposta aceita, me cortou em torno de uma solução que usa a macro __COUNTER__ para instanciar uma vez de tipo is_complete<T, int> diferente da macro IS_COMPLETE é usado. No entanto, com gcc, eu não poderia obter SFINAE para o trabalho em primeiro lugar.

Resolver este requer realizar o cálculo no argumento padrão do modelo característica, como a tentativa de alterar a definição de um modelo viola a regra ODR (embora uma combinação de __COUNTER__ e namespace {} pode contornar ODR).

Este é escrito em C ++ 11, mas pode ser ajustado para trabalhar em C ++ 03 modo de um moderadamente recente compilador C ++ 11-compatível.

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

Demonstração online.

O argumento padrão é avaliada onde o modelo é chamado, para que ele possa contextualmente alternar entre diferentes definições. Não há necessidade de uma especialização e definição diferente em cada utilização; você só precisa de um para true e um para false.

A regra é dada em §8.3.6 / 9, que se aplica igualmente aos argumentos função padrão e modelo padrão-argumentos:

argumentos padrão são avaliadas cada vez que a função é chamada.

Mas cuidado, usando isso dentro de um modelo é quase certo que violam a ODR. Um modelo instanciado em um tipo incompleto não deve fazer nada de forma diferente de se fosse instanciado em um tipo completa. Eu pessoalmente só deseja isso por um static_assert.

A propósito, este princípio também pode ser útil se você quiser ir por outro caminho e implementar a funcionalidade do __COUNTER__ usando templates e sobrecarga.

Apenas repicando no sinal de que uma resposta (não dado por mim) a uma pergunta não relacionada dá uma solução para o modelo is_complete<T>.

A resposta é aqui . Eu não estou colando-o abaixo a fim de não erroneamente obter crédito por isso.

Eu não consigo encontrar nada no padrão que garante que sizeof em um tipo incompleto renderá 0. Ele requer, no entanto, que, se T é incompleta em algum momento, mas completou mais tarde naquela unidade de tradução, que todas as referências a T referem-se ao mesmo tipo - assim como eu lê-lo, mesmo se T é incompleta, onde o modelo foi invocado, ele seria obrigado a dizer que foi completo se T é completado em algum lugar nessa unidade de tradução

.
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top