Meu entendimento é que C ++ permite que membros const estáticos sejam definidos dentro de uma classe, desde que seja um tipo inteiro.
Por que, então, o código a seguir fornece um erro de vinculador?
#include <algorithm>
#include <iostream>
class test
{
public:
static const int N = 10;
};
int main()
{
std::cout << test::N << "\n";
std::min(9, test::N);
}
O erro que recebo é:
test.cpp:(.text+0x130): undefined reference to `test::N'
collect2: ld returned 1 exit status
Curiosamente, se eu comentar a chamada para std :: min, o código compila e vincula perfeitamente (embora test :: N também seja referenciado na linha anterior).
Alguma ideia do que está acontecendo?
Meu compilador é o gcc 4.4 no Linux.
c++
static
declaration
definition
HighCommander4
fonte
fonte
char
, você pode defini-lo comoconstexpr static const char &N = "n"[0];
. Observe o&
. Acho que isso funciona porque as strings literais são definidas automaticamente. Estou um pouco preocupado com isso - pode se comportar de forma estranha em um arquivo de cabeçalho entre diferentes unidades de tradução, já que a string provavelmente estará em vários endereços diferentes.inline const int N = 10
, que até onde sei ainda tem um armazenamento em algum lugar definido pelo vinculador. Palavra-chave embutida também pode ser usada neste caso para fornecer definição de variável estática dentro do teste de definição de classe.Respostas:
Meu entendimento é que C ++ permite que membros const estáticos sejam definidos dentro de uma classe, desde que seja um tipo inteiro.
Você está certo. Você tem permissão para inicializar integrais const estáticos na declaração de classe, mas isso não é uma definição.
http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=/com.ibm.xlcpp8a.doc/language/ref/cplr038.htm
Curiosamente, se eu comentar a chamada para std :: min, o código compila e vincula perfeitamente (embora test :: N também seja referenciado na linha anterior).
Alguma ideia do que está acontecendo?
std :: min recebe seus parâmetros por referência const. Se os pegasse por valor, você não teria esse problema, mas como você precisa de uma referência, também precisa de uma definição.
Aqui está o capítulo / versículo:
9.4.2 / 4 - Se um
static
membro de dados for do tipoconst
integral ouconst
enumeração, sua declaração na definição da classe pode especificar um inicializador de constante que deve obrigatoriamente ser uma expressão de constante integral (5.19). Nesse caso, o membro pode aparecer em expressões constantes integrais. O membro ainda deve ser definido em um escopo de namespace se for usado no programa e a definição de escopo de namespace não deve conter um inicializador .Consulte a resposta de Chu para uma possível solução alternativa.
fonte
5
a umconst int&
. Então, por que não tratar os OPstest::N
como o literal correspondente?O exemplo de Bjarne Stroustrup em seu FAQ C ++ sugere que você está correto e só precisa de uma definição se você pegar o endereço.
Ele diz: "Você pode obter o endereço de um membro estático se (e somente se) ele tiver uma definição fora da classe" . O que sugere que funcionaria de outra forma. Talvez sua função min invoque endereços de alguma forma nos bastidores.
fonte
std::min
toma seus parâmetros por referência, razão pela qual uma definição é necessária.template<class K, class V, class C> const typename AE<K,V,C>::KeyContainer::size_type AE<K,V,C>::c7;
onde KeyContainer é um typedef de std :: vector <K>. Deve-se listar todos os parâmetros do modelo e escrever typename porque é um tipo dependente. Talvez alguém ache este comentário útil. No entanto, agora me pergunto como exportar isso em uma DLL porque a classe de modelo é, obviamente, em um cabeçalho. Preciso exportar c7 ???Outra forma de fazer isso, para tipos inteiros, é definir constantes como enums na classe:
fonte
Não apenas int's. Mas você não pode definir o valor na declaração da classe. Se você tem:
no arquivo .h, então você deve ter:
no arquivo .cpp.
fonte
static const
membro integral na definição da classe. Mas isso ainda não define aquele membro. Consulte a resposta de Noah Roberts para obter detalhes.Esta é outra maneira de contornar o problema:
(Acho que a resposta do Crazy Eddie descreve corretamente por que o problema existe.)
fonte
std::min(9, +test::N);
A partir do C ++ 11, você pode usar:
static constexpr int N = 10;
Teoricamente, isso ainda requer que você defina a constante em um arquivo .cpp, mas, desde que você não obtenha o endereço
N
dela, é muito improvável que qualquer implementação do compilador produza um erro;).fonte
Não, 3.1 §2 diz:
fonte