Alguém pode explicar por que o código a seguir não será compilado? Pelo menos em g ++ 4.2.4.
E mais interessante, por que ele será compilado quando eu converter MEMBER para int?
#include <vector>
class Foo {
public:
static const int MEMBER = 1;
};
int main(){
vector<int> v;
v.push_back( Foo::MEMBER ); // undefined reference to `Foo::MEMBER'
v.push_back( (int) Foo::MEMBER ); // OK
return 0;
}
Respostas:
Você realmente precisa definir o membro estático em algum lugar (após a definição da classe). Tente o seguinte:
Isso deve se livrar da referência indefinida.
fonte
O problema ocorre devido a um conflito interessante de novos recursos do C ++ e o que você está tentando fazer. Primeiro, vamos dar uma olhada na
push_back
assinatura:Está esperando uma referência a um objeto do tipo
T
. Sob o antigo sistema de inicialização, esse membro existe. Por exemplo, o código a seguir compila perfeitamente:Isso ocorre porque existe um objeto real em algum lugar que possui esse valor armazenado. Se, no entanto, você mudar para o novo método de especificar membros const estáticos, como você fez acima,
Foo::MEMBER
não será mais um objeto. É uma constante, um pouco semelhante a:Mas sem as dores de cabeça de uma macro de pré-processador (e com segurança de tipo). Isso significa que o vetor, que está esperando uma referência, não pode obter um.
fonte
(int)
) ocorre na unidade de tradução com visibilidade perfeita da constante eFoo::MEMBER
não é mais usada por odr . Isso contrasta com a primeira chamada de função, onde uma referência é passada e avaliada em outro lugar.void push_back( const T& value );
?const&
pode ligar com rvalues.O padrão C ++ requer uma definição para seu membro const estático, se a definição for necessária de alguma forma.
A definição é necessária, por exemplo, se o endereço for usado.
push_back
toma seu parâmetro por referência const e, portanto, estritamente o compilador precisa do endereço do seu membro e você precisa defini-lo no espaço para nome.Quando você lança explicitamente a constante, cria um temporário e é esse temporário que é vinculado à referência (sob regras especiais no padrão).
Este é um caso realmente interessante e, na verdade, acho que vale a pena levantar uma questão para que o std seja alterado para ter o mesmo comportamento do seu membro constante!
Embora, de uma maneira estranha, isso possa ser visto como um uso legítimo do operador '+' unário. Basicamente, o resultado de
unary +
é um rvalue e, portanto, as regras para vincular rvalues a referências const se aplicam e não usamos o endereço do nosso membro const estático:fonte
push_back
era aconst &
. O uso do membro resultou diretamente no membro sendo vinculado à referência, o que exigia que ele tivesse um endereço. No entanto, adicionar o+
cria um temporário com o valor do membro. A referência então se liga àquele temporário em vez de exigir que o membro tenha um endereço.Aaa.h
Aaa.cpp
fonte
Não faço ideia por que o elenco funciona, mas Foo :: MEMBER não é alocado até a primeira vez que o Foo é carregado, e como você nunca o carrega, nunca é alocado. Se você tivesse uma referência a um Foo em algum lugar, provavelmente funcionaria.
fonte
Com o C ++ 11, o acima seria possível para tipos básicos como
A
constexpr
peça cria uma expressão estática em oposição a uma variável estática - e se comporta exatamente como uma definição de método embutido extremamente simples. A abordagem se mostrou um pouco instável com constexprs de string C dentro de classes de modelo.fonte
Em relação à segunda pergunta: push_ref usa a referência como parâmetro e você não pode ter uma referência ao mem const constante de uma classe / estrutura. Depois de chamar static_cast, uma variável temporária é criada. E uma referência a esse objeto pode ser passada, tudo funciona bem.
Ou pelo menos meu colega que resolveu isso disse isso.
fonte