【问题标题】:struct with template object inside an templated class在模板化类中带有模板对象的结构
【发布时间】:2013-11-09 10:58:56
【问题描述】:

我正在尝试创建一个模板类来保存不同的对象,以了解一些对我来说是新的自写数据结构和 ptrs。 我被困在这一点上:

template <class T> class Linked_List
{

    struct Node
    {
        T data;
        Node* prev;
        Node* next;
        Node(T d, Node* p, Node* n) : data(d),
        prev(p), next(n) {}
    };

public:
    Linked_List();
    ~Linked_List();

    void push_back(T data);
    void push_front(T data);
    void insertAt(T data, int pos);

    T pop_back();
    T pop_front();

    int size();
    bool empty();

private:
    Node* tail;
    Node* head;
};

我收到此错误:'Linked_List&lt;T&gt;::Node::data' uses undefined class 'T'。 (使用VS2013)

我做错了什么?

谢谢


更新:

#include "Linked_List.h"


template<class T> Linked_List<T>::Linked_List()
{
    head = 0;
    tail = 0;
}

template<class T> Linked_List<T>::~Linked_List()
{
    {
        while (head)
        {
            Node* temp(head); //pointer to head
            head = head->next; // go to next
            delete temp; //delete the pointer
        }
    }
}

template <class T>
void Linked_List<T>::push_back(T data)
{
    //create the new Node
    tail = new Node(data, tail, NULL);
    if (tail->prev) //add to tail
        tail->prev->next = tail;
    if (empty()) // if empty its also the head
        head = tail;
}

template <class T>
void Linked_List<T>::push_front(T data)
{
    head = new Node(data, 0, tail);
    if (head->next)
        head->next->prev = head;
    if (empty())
        tail = head;
}

template <class T>
bool Linked_List<T>::empty()
{
    return (!head || !tail);
}

template <class T>
T Linked_List<T>::pop_back()
{
    if (empty())
        throw("Linked_list is empty!");
    //pointer to the element we want to have
    Node* temp(tail);
    //set the tail to prev
    tail = tail->prev;
    //get the data
    T data = temp->data;

    //the prev does not have a next now
    if (tail)
        tail->next = 0;
    else
        head = 0;

    //delete the node which held our data
    delete temp;
    //return the data
    return data;
}

template <class T>
T Linked_List<T>::pop_front()
{
    if (empty())
        throw("Linked_list is empty!");
    //pointer to the element we want to have
    Node* temp(head);
    //set the tail to prev
    head = head->next;
    //get the data
    T data = temp->data;

    //the prev does not have a next now
    if (head)
        head->prev = 0;
    else
        tail = 0;

    //delete the node which held our data
    delete temp;
    //return the data
    return data;
}

新的堆栈跟踪,如果我想像这样简单地使用它

int main(){
    Linked_List<int> list;
    for (int i = 0; i < 20; i++)
    {
        list.push_back(i);
    }

    for (int j = 0; j < 20; j++)
    {
        cout <<  list.pop_back() << endl;
    }
}

错误:

 Error  1   error LNK2019: unresolved external symbol "public: __thiscall Linked_List<int>::Linked_List<int>(void)" (??0?$Linked_List@H@@QAE@XZ) referenced in function _main   C:\Users\...\Documents\Visual Studio 2013\Projects\Double_Linked_List\Double_Linked_List\main.obj   Double_Linked_List
    Error   2   error LNK2019: unresolved external symbol "public: __thiscall Linked_List<int>::~Linked_List<int>(void)" (??1?$Linked_List@H@@QAE@XZ) referenced in function _main  C:\Users\...\Documents\Visual Studio 2013\Projects\Double_Linked_List\Double_Linked_List\main.obj   Double_Linked_List
    Error   3   error LNK2019: unresolved external symbol "public: void __thiscall Linked_List<int>::push_back(int)" (?push_back@?$Linked_List@H@@QAEXH@Z) referenced in function _main C:\Users\...\Documents\Visual Studio 2013\Projects\Double_Linked_List\Double_Linked_List\main.obj   Double_Linked_List
    Error   4   error LNK2019: unresolved external symbol "public: int __thiscall Linked_List<int>::pop_back(void)" (?pop_back@?$Linked_List@H@@QAEHXZ) referenced in function _main    C:\Users\...\Documents\Visual Studio 2013\Projects\Double_Linked_List\Double_Linked_List\main.obj   Double_Linked_List
    Error   5   1   error LNK1120: 4 unresolved externals   C:\Users\...\Documents\Visual Studio 2013\Projects\Double_Linked_List\Debug\Double_Linked_List.exe  1   Double_Linked_List

【问题讨论】:

  • 上面的代码没有问题。我的水晶球告诉我你选择不包含的看不见的代码是实现,你可能没有正确定义模板函数。例如:template&lt;class T&gt; void Linked_List&lt;T&gt;::push_back(T data){ .. }。注意方法定义前面的template &lt;class T&gt;。此外,这个 all 与类 def 属于同一个头文件。
  • Linked_List&lt;class T&gt;::Linked_List() 语法无效。使用template&lt;class T&gt; Linked_List&lt;T&gt;::Linked_List()(还要注意模板只能在he​​aders中定义)
  • 您的代码在添加必要的标头后编译良好。请确保在使用Linked_List&lt;T&gt; 的每个源文件中,Linked_List&lt;T&gt; 成员函数的定义(函数体)为#included。见Why can templates only be implemented in the header file?
  • 如果Linked_List&lt;T&gt; 的成员函数所在的文件是.cpp(即如果您的问题中以#include "Linked_List.h" 开头的代码块是.cpp 文件),那么您确实有我刚刚链接的答案中描述的问题。将此文件的所有内容剪切并粘贴到头文件的末尾,并删除以前包含代码的 .cpp。
  • “如果我过去/将其包含在 .h 中,我会遇到编译错误,例如无法识别的模板声明/定义等等” 请在您的问题中发布哪个代码块文件(现在)以及如何(尤其是按顺序)包含标题。

标签: c++ templates struct linked-list


【解决方案1】:

链接器非常清楚:您缺少这些方法的定义。编译器没有抱怨,因为它看到了 Linked_List 类的声明,但是在处理模板时,这还不够。

为了使模板实例化成功,所有模板定义都需要可见。由于您在 cpp 文件中实现了模板类的方法(人们通常在头文件或 impl 文件中执行此操作),因此您需要在实例化模板的位置包含该文件。在您的具体示例中,在 main.cpp 中:

#include <iostream>
#include "Linked_List.cpp"   // !!!


int main(){
    Linked_List<int> list;
    for (int i = 0; i < 20; i++)
    {
        list.push_back(i);
    }

    for (int j = 0; j < 20; j++)
    {
        std::cout <<  list.pop_back() << std::endl;
    }
}

您可以在源文件中显式执行此操作,而不是包含植入文件,并让编译器隐式实例化模板。在这种情况下,将此行添加到 Linked_List.cpp 的末尾:

template class Linked_List<int>;

但在这种情况下,您将无法创建具有不同模板参数(int 除外)的对象。


第三个选项是第一个选项的变体。在标题末尾包含源文件。

标题

// header.hpp
#ifndef HEADER_HPP
#define HEADER_HPP

template< typename T >
struct A
{
    void foo();
};

#include "source.impl"

#endif

来源

// source.impl

#include "header.hpp"

template< typename T >
void A::foo()
{
}

主要

// main.cpp

#include "header.hpp"

int main()
{
  A<int> a;
  a.foo();
}

【讨论】:

  • 我不建议在 main.cpp 中使用 #include "Linked_List.cpp"。 (另外,在第二部分中,“std:: 结尾”是什么意思?)(另外,“other then” → “other than”。)我建议阅读the linked question 的答案(感谢DyP's comment)。
  • @gx_ 正如我所说:要么实现标头中的所有内容,要么包含源代码,要么显式实例化。错误修复
  • @BЈовићeither 实现标题中的所有内容都是很好的解决方案
【解决方案2】:

我猜你已经把模板类的定义和它的方法的实现放在两个文件中,就像你对普通的非模板类所做的那样;你只需在 main.cpp 中包含定义链接列表的头文件。

请参考这个帖子了解为什么你不能这样做

Why can templates only be implemented in the header file?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-22
    • 1970-01-01
    • 2021-11-28
    • 2012-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多