C++ — неопределенная ссылка на недавно созданный класс!

StackOverflow https://stackoverflow.com/questions/1001375

Вопрос

Я только что создал этот новый класс:

//------------------------------------------------------------------------------
#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
//------------------------------------------------------------------------------

Определение класса:

//------------------------------------------------------------------------------
#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_;

}

Теперь проблема в том, что когда я пытаюсь использовать его в своем коде как статический член другого класса:

// VehicleManager.h
#ifndef MULTITHREADEDVECTOR_H
#define MULTITHREADEDVECTOR_H

#include "MultithreadedVector.h"
#include "Vehicle.h"
class Foo {

   public:
     // stuffs
   private:
     static MultithreadedVector<Vehicle> vehicles_; 
     ...
}

#endif

Затем внутри:VehicleManager.cpp

#include "VehicleManager.h"

MultithreadedVector<Vehicle> VehicleManager::vehicles_;

void VehicleManager::Method() {

  Vehicle vehicle;
  VehicleManager::vehicles_.push_back(vehicle);

}

Но он не компилируется :(, я каждый раз получаю это сообщение об ошибке:

C:\***\VehicleManager.cpp|188|undefined reference to `MultithreadedVector<Vehicle>::push_back(Vehicle)'|

Я действительно не понимаю, почему, особенно потому, что я определил член статического класса в глобальной области видимости VehicleManager.cpp.

ПС:Я использую Code::Blocks.

Спасибо !

Это было полезно?

Решение

Вот что произойдет, если слепо переместить реализацию шаблона класса в файл cpp.

Чтобы это работало, вы должны точно знать, для каких типов T вы будете создавать экземпляр шаблона класса и указывать их в файле cpp.

В этом случае поместите это в файл cpp:

template class MultithreadedVector<Vehicle>;

Обратите внимание, что файл cpp должен знать о Vehicle .

Другие советы

Большинство компиляторов C ++ не позволяют разделять объявления шаблонов и определения шаблонов. Вам нужно поместить полное определение ваших шаблонных классов в один файл .h, а не разбивать их на файлы .h и .cpp.

Полный код реализации шаблона должен быть виден компилятору в той точке, в которой он видит использование шаблона, чтобы он мог создать экземпляр шаблона и скомпилировать его в объектный код, который впоследствии можно будет связать.

Определите код шаблона в том же заголовочном файле, в котором объявлен шаблон.

Я думаю, что есть два случая, как можно использовать шаблоны.

  1. Предоставление общего кода для произвольного набора соответствующих типов.
  2. Предоставление общего кода для фиксированного набора типов

Для второго шаблоны в шапку помещать не нужно:Так как вы заранее точно знаете, с какими типами используется ваш шаблон.Вы вполне можете определить функцию-член шаблона класса или шаблон функции в отдельной единице перевода без ошибок компоновщика.Некоторые люди продолжают учить других, что это невозможно, и этим запутывают дело.

Но я думаю, что от этих двух случаев зависит, хотите ли вы разделить объявление и определение на разные единицы перевода или нет.

  • Если вы хотите использовать вариант 1, вам всегда нужно иметь определение в заголовке (независимо от того, включено ли оно в файлы со специальными именами, например .ipp, .tcc или что-то еще).Я знаю только один интерфейс C++, который поддерживает отделение определений от объявлений даже в этом случае, а именно интерфейс EDG (edison design group), используемый компиляторами Intel и Comeau, которые реализуют export.Некоторые считают это ключевое слово ошибкой, и большинство компиляторов его не реализуют.

  • А если вы хотите использовать вариант 2, то не стоит помещать определения в заголовок, потому что не будет смысла это делать:Вы просто явно создадите экземпляры необходимых функций и классов для фиксированного набора типов.В этом втором сценарии вы используете шаблон, чтобы избавить себя от бремени поддержки, возможно, избыточного кода, и у вас есть возможность ввести специальное поведение для некоторых типов в некоторых случаях.

Ваш сценарий явно относится к ситуации случая 1, поэтому вам придется поместить свои определения в заголовок.

Похоже, у вас ошибка копирования и вставки в VehicleManager.h:

#ifndef MULTITHREADEDVECTOR_H
#define MULTITHREADEDVECTOR_H

Это запрещает включение заголовочного файла, в котором определен класс Foo.

В большинстве случаев вы не можете записать реализацию шаблона в файл cpp. Переместите реализацию шаблона в файл заголовка, чтобы компилятор мог правильно его создать.

Помимо других ответов:

Вы также должны охранять get_container () . Этот метод в основном копирует элементы container _ и, следовательно, должен быть защищен.

template<class T>
vector<T> MultithreadedVector<T>::get_container() 
{
    return container_;
}

Шаблон в некотором роде является продвинутым, специализированным видом макросов. На самом деле вы не можете скомпилировать определение шаблона отдельно, как это выглядит, как будто вы пытаетесь это сделать.

Для большинства людей это означает, что они даже не удосуживаются отделить определения teplate от своих объявлений. У меня есть один сотрудник, который делает этот шаг дальше и отказывается отделяться < em> не шаблонные определения и объявления тоже.

Если вы хотите добавить определение шаблона из объявления, у вас есть несколько вариантов.

Первый вариант - использовать C ++ " export " ключевое слово. Проблема этого, казалось бы, простого решения заключается в том, что никто его не поддерживает . Это слишком сложно для разработчиков компиляторов.

Второй вариант - использовать файл третьего типа , часто с тегами " .ipp " ;, для объявлений. Хитрость заключается в том, что это все еще файл, который должен быть «включен», но, будучи отдельным файлом, вам нужно всего лишь включить его в «.cpp»; файлы. Я обнаружил, что моему компоновщику не нравится, если я #include a. Quot; .ipp " в более чем одном ".cpp" файл в одной программе, так что вам нужно выбрать одну из них.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top