Pergunta

Você poderia dar um exemplo onde static_assert(...) 'C++0x' resolveria o problema na mão elegantemente?

Estou familiarizado com assert(...) de tempo de execução. Quando eu deve preferir static_assert(...) sobre assert(...) regular?

Além disso, em boost existe algo chamado BOOST_STATIC_ASSERT, é o mesmo que static_assert(...)?

Foi útil?

Solução

Em cima da minha cabeça ...

#include "SomeLibrary.h"

static_assert(SomeLibrary::Version > 2, 
         "Old versions of SomeLibrary are missing the foo functionality.  Cannot proceed!");

class UsingSomeLibrary {
   // ...
};

Assumindo que SomeLibrary::Version é declarado como um const estático, em vez de ser #defined (como seria de esperar em uma biblioteca C ++).

O contraste com a necessidade de SomeLibrary realmente compilação e seu código, link de tudo, e rodar o executável única então para descobrir que você gastou 30 minutos compilar uma versão incompatível do SomeLibrary.

@Arak, em resposta ao seu comentário: sim, você pode ter static_assert apenas sentados onde quer que, a partir do olhar dela:

class Foo
{
    public: 
        static const int bar = 3;
};

static_assert(Foo::bar > 4, "Foo::bar is too small :(");

int main()
{ 
    return Foo::bar;
}
$ g++ --std=c++0x a.cpp
a.cpp:7: error: static assertion failed: "Foo::bar is too small :("

Outras dicas

assert

estática é usado para fazer afirmações em tempo de compilação. Quando a afirmação estática falhar, o programa simplesmente não compila. Isso é útil em situações diferentes, como, por exemplo, se você implementar algumas funcionalidades pelo código que criticamente depende objeto unsigned int ter exatamente 32 bits. Você pode colocar um assert estático como este

static_assert(sizeof(unsigned int) * CHAR_BIT == 32);

em seu código. Em outra plataforma, com unsigned int diferente tamanho digite a compilação irá falhar, desenhando assim a atenção do desenvolvedor para a parte problemática do código e aconselhando-os a re-implantar ou re inspecionar-lo.

Para outro exemplo, você pode querer passar algum valor integral como um ponteiro void * para uma função (um hack, mas útil às vezes) e você quer ter certeza de que o valor integral vai se encaixar no ponteiro

int i;

static_assert(sizeof(void *) >= sizeof i);
foo((void *) i);

Você pode querer ativo que tipo char é assinado

static_assert(CHAR_MIN < 0);

ou que a divisão integral com rodadas valores negativos a zero

static_assert(-5 / 2 == -2);

E assim por diante.

afirmações em tempo de execução em muitos casos, pode ser usado em vez de afirmações estáticos, mas apenas afirmações de tempo de execução de trabalho em tempo de execução e somente quando o controle passa sobre a afirmação. Por esta razão a não declaração de tempo de execução podem permanecer dormentes, sem ser detectado por longos períodos de tempo.

É claro que a expressão na afirmação estática tem de ser uma constante em tempo de compilação. Não pode ser um valor de tempo de execução. Para valores em tempo de execução você não tem outra escolha a não usar o assert comum.

Eu usá-lo para garantir minhas suposições sobre o comportamento do compilador, cabeçalhos, bibliotecas e até mesmo meu próprio código estão corretas. Por exemplo, aqui eu verificar que a estrutura tenha sido corretamente embalado para o tamanho esperado.

struct LogicalBlockAddress
{
#pragma pack(push, 1)
    Uint32 logicalBlockNumber;
    Uint16 partitionReferenceNumber;
#pragma pack(pop)
};
BOOST_STATIC_ASSERT(sizeof(LogicalBlockAddress) == 6);

Em stdio.h um fseek() classe de embrulho, tenho tido alguns atalhos com enum Origin e verificação de que esses atalhos alinhar com as constantes definidas pelo stdio.h

uint64_t BasicFile::seek(int64_t offset, enum Origin origin)
{
    BOOST_STATIC_ASSERT(SEEK_SET == Origin::SET);

Você deve preferir static_assert sobre assert quando o comportamento é definido em tempo de compilação, e não em tempo de execução, tais como os exemplos que eu dei acima. Um exemplo em que este é não o caso iria incluir parâmetro e verificação de código de retorno.

BOOST_STATIC_ASSERT é um pré-C ++ 0x macro que gera código ilegal se a condição não for satisfeita. As intenções são as mesmas, embora static_assert é padronizado e pode fornecer diagnósticos melhor compilador.

BOOST_STATIC_ASSERT é um invólucro de plataforma cruzada para a funcionalidade static_assert.

Atualmente estou usando static_assert, a fim de fazer cumprir "Conceitos" em uma classe.

exemplo:

template <typename T, typename U>
struct Type
{
  BOOST_STATIC_ASSERT(boost::is_base_of<T, Interface>::value);
  BOOST_STATIC_ASSERT(std::numeric_limits<U>::is_integer);
  /* ... more code ... */
};

Isto irá causar um erro de tempo de compilação se qualquer uma das condições acima não sejam cumpridos.

Um uso de static_assert poderia ser a de garantir que a estrutura (que é uma interface com o mundo exterior, tal como uma rede ou arquivo) é exatamente o tamanho que você espera. Este seria pegar casos em que alguém adiciona ou modifica um membro da estrutura sem perceber as conseqüências. O static_assert iria buscá-lo e alertar o usuário.

Na ausência de conceitos pode-se usar static_assert para simples e legível em tempo de compilação verificação de tipo, por exemplo, nos modelos:

template <class T>
void MyFunc(T value)
{
static_assert(std::is_base_of<MyBase, T>::value, 
              "T must be derived from MyBase");

// ...
}

Isto não responde diretamente à pergunta original, mas faz um estudo interessante sobre como aplicar essas verificações de tempo de compilação antes de C ++ 11.

Capítulo 2 (Seção 2.1) de design moderno C ++ por implementos Andrei Alexanderscu este idéia de afirmações de compilação momento como este

template<int> struct CompileTimeError;
template<> struct CompileTimeError<true> {};

#define STATIC_CHECK(expr, msg) \
{ CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; } 

Compare o macro STATIC_CHECK () e static_assert ()

STATIC_CHECK(0, COMPILATION_FAILED);
static_assert(0, "compilation failed");
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top