Ошибка компиляции C ++ в Visual Studio 10 - PullRequest
4 голосов
/ 16 июля 2011

Я получаю следующую ошибку при компиляции этой простой программы с использованием Visual Studio:

error LNK2019: unresolved external symbol "public: void __thiscall CoList<int>::enqueue(int)" (?enqueue@?$CoList@H@@QAEXH@Z) referenced in function _main

error LNK2019: unresolved external symbol "public: virtual __thiscall CoList<int>::~CoList<int>(void)" (??1?$CoList@H@@UAE@XZ) referenced in function _main

error LNK2019: unresolved external symbol "public: int __thiscall CoList<int>::dequeue(void)" (?dequeue@?$CoList@H@@QAEHXZ) referenced in function _main

error LNK2019: unresolved external symbol "public: int __thiscall CoList<int>::count(void)" (?count@?$CoList@H@@QAEHXZ) referenced in function _main

error LNK2019: unresolved external symbol "public: __thiscall CoList<int>::CoList<int>(void)" (??0?$CoList@H@@QAE@XZ) referenced in function _main

error LNK1120: 5 unresolved externals

Моя программа очень проста. Я не использую внешние библиотеки, только заголовки «iostream» и «exception» ... Вот полный код:

CoList.h

#pragma once

#include "CoListItem.h"

template <class T>
class CoList
{

public:

    CoList();
    virtual ~CoList();

    void enqueue(T value);
    T dequeue();
    T *peek();
    int count();

private:
    CoListItem<T> *m_root;
    int m_count;

};

CoListItem.h

#pragma once

template <class T>
class CoListItem
{

public:

    CoListItem();
    virtual ~CoListItem();

    T value;
    CoListItem *next;

};

CoList.cpp

#include "CoList.h"
#include <exception>

template <class T>
CoList<T>::CoList()
{
}

template <class T>
CoList<T>::~CoList()
{
}

template <class T>
void CoList<T>::enqueue(T value)
{
    if (this->m_root != NULL) {
        this->m_root = new CoListItem<T>();
        this->m_root->value = value;
        this->m_root->next = NULL;
    } else {
        CoListItem<T> *tempitem = new CoListItem<T>();
        tempitem->value = value;
        tempitem->next = this->m_root;

        this->m_root = tempitem;
    }

    this->m_count++;
}

template <class T>
T CoList<T>::dequeue()
{
    if (this->m_root == NULL) {
        throw std::exception();
    } else {
        T retval = this->m_root->value;
        CoListItem *next = this->m_root->next;
        delete this->m_root;
        this->m_root = next;

        return retval;
    }
}

template <class T>
T *CoList<T>::peek()
{
    if (this->m_root == NULL) {
        return NULL;
    } else {
        return *this->dequeue();
    }
}

template <class T>
int CoList<T>::count()
{
    return this->m_count;
}

CoListItem.cpp

#include "CoListItem.h"

template <class T>
CoListItem<T>::CoListItem()
{
}


template <class T>
CoListItem<T>::~CoListItem()
{
}

и, наконец, основная функция:

#include <iostream>
#include "CoList.h"
#include "CoListItem.h"

using namespace std;

int main(int argc, char *argv[])
{
    CoList<int> list;

    for(int i = 0; i < 10; i++)
        list.enqueue(i);

    cout << "Count: " << list.count() << endl;

    for(int i = 0; i < 10; i++)
        cout << "Item: " << list.dequeue() << endl;

    cout << "Count: " << list.count() << endl;

    int wait = 0;
    cin >> wait;
}

Как видите, это очень простая реализация очереди, использующая связанный список ...

Ответы [ 4 ]

4 голосов
/ 16 июля 2011

Определения шаблонов функций (включая функции-члены шаблонов классов) должны быть в файле .h, чтобы они присутствовали в каждом файле cpp, в котором они используются. Вот как работают шаблоны. Вы не можете поместить определения в файл cpp. Технически, есть ключевое слово export, которое разрешает это, но так как почти ни одна реализация не поддерживала его, оно было удалено в новом стандарте.

Читать это: Модель включения

1 голос
/ 16 июля 2011

template определения должны быть видны коду, который его использует.Для этого

  1. Поместите все определения в файл ".h"
  2. Поместите определения в файл ".cpp" (для разделения кода) и #include that ".cpp "file

Например, в вашем случае вы можете #include "CoList.cpp" вместо "CoList.h".И так далее.

0 голосов
/ 16 июля 2011

Рассмотрим шаблонную функцию, которая принимает T и выполняет модуль (%) или простое сложение (+) в этом отношении.

template <class T>
T GetT(T t1, T t2)
{
    return t1%t2;
}

В этом коде вы видите NO ERROR.Хорошо.Когда я передаю два целых числа, он компилируется:

GetT(10,20);

Но когда я передаю float / double, он НЕ компилируется:

GetT(10.6, 20.5);

Компилятор выдаст: error C2296: '%' : illegal, left operand has type 'double' и другие связанные ошибки.Дело в том, что код шаблона не компилируется, пока вы не создадите его хотя бы один раз для определенного типа данных.Код шаблона остается ненужным - компилятору все равно, что на самом деле внутри кода.В вашем случае CPP - это не что иное, как текстовый файл, который компилятор проигнорировал - все это.

Сказав, что, когда я использую оператор + вместо оператора %, он будет работать для всехбазовые типы данных, но не для классов, которые отсутствуют operator +.В этом случае компилятор снова скомпилирует материал шаблона для этого типа данных (класса).

Существуют случаи, когда компилятор и компоновщик работают вместе, чтобы уменьшить окончательный размер двоичного кода, когда они видят, что некоторый код дублируется и будет одинаковым для всех / нескольких типов данных.Но это другой случай.

0 голосов
/ 16 июля 2011

Это прямо из легендарной книги Николая Джозутиса ,

C ++: полное руководство

скомпилировано дважды:

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

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


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

...