C ++ - referência Undefined a uma classe recém-criado!
-
05-07-2019 - |
Pergunta
Acabei de criar esta nova classe:
//------------------------------------------------------------------------------
#ifndef MULTITHREADEDVECTOR_H
#define MULTITHREADEDVECTOR_H
//------------------------------------------------------------------------------
#include <vector>
#include <GL/GLFW.h>
//------------------------------------------------------------------------------
template<class T>
class MultithreadedVector {
public:
MultithreadedVector();
void push_back(T data);
void erase(typename std::vector<T>::iterator it);
std::vector<T> get_container();
private:
std::vector<T> container_;
GLFWmutex th_mutex_;
};
//------------------------------------------------------------------------------
#endif // MULTITHREADEDVECTOR_H_INCLUDED
//------------------------------------------------------------------------------
A definição da classe:
//------------------------------------------------------------------------------
#include "MultithreadedVector.h"
//------------------------------------------------------------------------------
using namespace std;
//------------------------------------------------------------------------------
template<class T>
MultithreadedVector<T>::MultithreadedVector() {
th_mutex_ = glfwCreateMutex();
}
template<class T>
void MultithreadedVector<T>::push_back(T data) {
glfwLockMutex(th_mutex_);
container_.push_back(data);
glfwUnlockMutex(th_mutex_);
}
template<class T>
void MultithreadedVector<T>::erase(typename vector<T>::iterator it) {
glfwLockMutex(th_mutex_);
container_.erase(it);
glfwUnlockMutex(th_mutex_);
}
template<class T>
vector<T> MultithreadedVector<T>::get_container() {
return container_;
}
Agora, o problema é que quando eu tento usá-lo no meu código como um membro estático de outra classe:
// VehicleManager.h
#ifndef MULTITHREADEDVECTOR_H
#define MULTITHREADEDVECTOR_H
#include "MultithreadedVector.h"
#include "Vehicle.h"
class Foo {
public:
// stuffs
private:
static MultithreadedVector<Vehicle> vehicles_;
...
}
#endif
Então, dentro: VehicleManager.cpp
#include "VehicleManager.h"
MultithreadedVector<Vehicle> VehicleManager::vehicles_;
void VehicleManager::Method() {
Vehicle vehicle;
VehicleManager::vehicles_.push_back(vehicle);
}
Mas isso não compilar :(, eu recebo este erro cada vez que msg:
C:\***\VehicleManager.cpp|188|undefined reference to `MultithreadedVector<Vehicle>::push_back(Vehicle)'|
Eu realmente não entendo por que, especialmente que eu tenha definido o membro da classe estática no escopo global de VehicleManager.cpp.
PS:. Estou usando o Code :: Blocks
Obrigado!
Solução
Isso é o que vai acontecer quando se deslocam cegamente uma implementação modelo de classe para um arquivo cpp.
Para fazer esse trabalho, você deve saber exatamente para quais tipos de T você vai instanciar o modelo de classe e especificá-los no arquivo cpp.
Neste caso, colocar isso no arquivo cpp:
template class MultithreadedVector<Vehicle>;
Note que o arquivo cpp deve saber sobre Vehicle
então.
Outras dicas
A maioria C ++ compiladores não permitem declarações modelo separados e definitiions modelo. Você precisa colocar a definição completa de suas classes de modelo em um único arquivo .h, e não dividi-los em arquivos e.cpp.
O código completo de execução modelo deve ser visível para o compilador no ponto em que vê o uso de modelo para que ele possa instanciar o modelo e compilá-lo em código objeto que pode ser depois ligados.
Definir o código do modelo no mesmo arquivo de cabeçalho como o modelo é declarada.
Eu acho que existem dois casos como se pode usar modelos
- Fornecer código genérico para um conjunto arbitrário de tipos em conformidade
- Fornecer código genérico para um conjunto fixo de tipos
Para o segundo, você não precisa colocar modelos para o cabeçalho: Desde que você sabe de antemão, precisamente, com que tipos seu modelo é usado. Você pode muito bem definir a função membro de um modelo de classe, ou um modelo função em uma unidade de tradução separado, sem erros de vinculador. Algumas pessoas mantêm ensinar aos outros que isso não é possível, e confundir a questão por este.
Mas eu acho que depende desses dois casos se deseja separar declaração e definição em diferentes unidades de tradução ou não.
-
Se você quiser caso de uso 1, você sempre quer ter a definição no cabeçalho (seja incluído por arquivos chamados especiais, como
.ipp
,.tcc
ou qualquer outro). Sei apenas de uma interface C ++ que suportes de separação definição de declarações, mesmo neste caso, é que o EDG (grupo de design Edison) interface, usado pelos compiladores da Intel e Comeau, que implementarexport
. Essa palavra-chave é visto como um misfeature por alguns, e a maioria dos compiladores não implementá-lo. -
E se você quiser usar o caso 2, não é bom para colocar as definições no cabeçalho, porque não haveria nenhuma razão para fazê-lo: Você só vai instanciar explicitamente as funções e classes necessárias para o conjunto fixo de tipos. Neste segundo cenário, você usar o modelo para salvar-se do fardo para manter o código possivelmente redundante, e tem a opção aberta para introduzir um comportamento especial para alguns tipos em alguns casos.
Seu cenário é claramente uma situação de caso 1, e assim você terá que colocar suas definições no cabeçalho.
Você parece ter uma cópia e colar erro no VehicleManager.h:
#ifndef MULTITHREADEDVECTOR_H
#define MULTITHREADEDVECTOR_H
Esta proíbe a inclusão do arquivo de cabeçalho, onde a classe Foo é definido.
Você não pode escrever a implementação do modelo no arquivo cpp na maioria dos casos. Mova a implementação de modelo para o arquivo de cabeçalho para que compilador pode instanciar-lo corretamente.
Além de outras respostas:
Você tem que get_container()
guarda também. Este método basicamente copia os elementos container_
e, portanto, deve ser vigiado.
template<class T>
vector<T> MultithreadedVector<T>::get_container()
{
return container_;
}
Um modelo de forma é uma espécie de avançado, especializado tipo de macro. Você não pode realmente compilar uma defintion modelo separadamente, como parece que você está tentando fazer.
Para a maioria das pessoas, isso significa que eles não se incomodam mesmo para separar Tepla definições de suas declarações. Eu tenho um colega de trabalho que leva isso um passo adiante , e se recusa a separar < em> não-template definições e declarações também.
Se você quiser colocar a definição de um modelo da declaração, você tem um par de opções embora.
A primeira opção é usar o C ++ palavra-chave "exportação". O problema com esta solução aparentemente simples é que ninguém suporta . É muito difícil para escritores de compiladores de implementar.
A segunda opção é usar um terceiro tipo de arquivo , muitas vezes com a tag ".ipp", para as declarações. O truque aqui é que ele ainda é um arquivo que deve ser "#included", mas sendo um arquivo separado, você só tem que incluí-lo em arquivos ".cpp". Eu encontrei minha vinculador não gostar se eu #include um ".ipp" em mais de um arquivo ".cpp" em um único programa, então você tem que escolher um ser o includer.