简体   繁体   English

c++聚合类型不完整,不能用模板类定义

[英]c++ aggregate has incomplete type and cannot be defined with template class

This is the first time that I have a Problem that I cant solve with simple googleing.这是我第一次遇到无法通过简单的谷歌搜索解决的问题。 I have a Problem with a Homework assignement in c++.我在 C++ 中的作业分配有问题。 As Startup, we are not allowed to change the main.cpp.作为 Startup,我们不允许更改 main.cpp。 The Task is, to write a double linked list and to use Template Classes.任务是,编写一个双链表并使用模板类。

I get the errors我得到了错误

aggregate Queue<std::__cxx11::basic_string<char> > q1' has incomplete type and cannot be defined Queue<string> q1;

and

variable 'Queue<double> q3' has initializer but incomplete type
Queue<double> q3(q2);

If I google those Errors, the answere is, that I probably have not properly declared my class in the header file or a similar declaration or definition mistake.如果我用谷歌搜索这些错误,答案是我可能没有在头文件或类似的声明或定义错误中正确声明我的类。 But I cant find the mistake I made.但是我找不到我犯的错误。

I have tryed different apporaches with the Constructor (with and without initializer list).我用构造函数尝试了不同的方法(有和没有初始化列表)。 I experimented with the spezialisations.我尝试了特殊化。 If I put the spezialisation of the friend operator<< in the header file (which I were thought to always do) I get this error:如果我将友元运算符<< 的特殊化放在头文件中(我认为总是这样做),我会收到此错误:

expected initializer before '<' token
 std::ostream& operator<< <std::string>

I hope you can help me.我希望你能帮助我。

Here is the main.cpp which should not be changed:这是不应更改的 main.cpp:

#include <iostream>
#include <iomanip>
#include <ctime>
#include <utility>
#include <string>

#include "Queue.hpp"


using namespace std;

int main()
{
    cout << boolalpha;

    Queue<string> q1;
    cout << "Queue q1 ist leer: " << q1.empty() << endl << endl;
    q1.push("Bergische");
    q1.push("Universitaet");
    q1.push("Wuppertal");
    cout << "Queue q1:" << endl << q1 << endl;
    cout << "Pop erstes Element: " << q1.pop() << endl << endl;
    cout << "Queue q1:" << endl << q1 << endl;

    Queue<double> q2;
    q2.push(3.1415);
    q2.push(2.7182);
    cout << "Queue q2:" << endl << q2 << endl;
    cout << "Groesse von q2: " << q2.size() << endl << endl;
    Queue<double> q3(q2);
    cout << "Queue q3 aus q2 mit Copy-Konstruktor: " << q3 << endl;

    Queue<int> q4;
    for(int i=0; i<100000000; ++i)
        q4.push(i);
    cout << "Groesse von q4: " << q4.size() << endl;

    cout << fixed << setprecision(8);
    cout << "Beginne Zeitmessung Copy-Konstruktor... " << flush;
    clock_t start = clock();
    Queue<int> q4copy(q4);
    clock_t end = clock();
    cout << (end-start)/(double)CLOCKS_PER_SEC << " Sekunden" << endl;

    cout << "Groesse von q4:     " << q4.size() << endl;
    cout << "Groesse von q4copy: " << q4copy.size() << endl;

    cout << "Beginne Zeitmessung Move-Konstruktor... " << flush;
    start = clock();
    Queue<int> q4move(move(q4));
    end = clock();
    cout << (end-start)/(double)CLOCKS_PER_SEC << " Sekunden" << endl;

    cout << "Groesse von q4:     " << q4.size() << endl;
    cout << "Groesse von q4move: " << q4move.size() << endl;

    return 0;
}

the Queue.hpp: Queue.hpp:

#ifndef QUEUE_HPP_
#define QUEUE_HPP_


#include <iostream>
#include <iomanip>
#include <ctime>
#include <utility>
#include <string>

template<typename T>
class Queue;

template<typename T>
class Queue_el{
private:
    Queue_el* pHeadEl;
    Queue_el* pTailEl;
    T data;
public:
    Queue_el(Queue_el* a = nullptr, Queue_el* b = nullptr);
    Queue_el(const Queue_el &q);
    ~Queue_el();

    Queue_el& operator=(Queue_el q);

    friend class Queue<T>;
    template<typename U>
    friend std::ostream& operator<<(std::ostream& os, const Queue_el<U> &q);
};

template<typename T>
class Queue{
private:
    Queue_el<T>* pHead;
    Queue_el<T>* pTail;
public:
    Queue(Queue_el<T>* a = nullptr, Queue_el<T>* b = nullptr);
    Queue(const Queue &q);
    ~Queue();
    Queue(Queue&& q);

    Queue& operator=(const Queue&q);
    Queue& operator=(Queue&& q);

    void push(T data) const;
    T pop() const;
    bool empty() const;
    int size() const;

    friend class Queue_el<T>;
    template <typename U>
    friend std::ostream& operator<<(std::ostream& os, const Queue<U> &q);


};



template<> class Queue_el<std::string>;
template<> class Queue_el<double>;
template<> class Queue_el<int>;

template<> class Queue<std::string>;
template<> class Queue<double>;
template<> class Queue<int>;


#endif /* QUEUE_HPP_ */

and the Queue.cpp:和 Queue.cpp:

#include "Queue.hpp"


template<typename T>
Queue<T>::Queue(Queue_el<T>* a, Queue_el<T>* b)
        :pHead(a), pTail(b)
{

};

template<typename T>
Queue<T>::Queue(const Queue<T> &q) {
    Queue_el<T> *buffer = nullptr;
    Queue_el<T> *bufferq = q.pHead;

    buffer = new Queue_el<T>;
    pHead = buffer;
    buffer = buffer->pTailEl;
    bufferq = bufferq->pTailEl;

    while (bufferq->pTailEl != nullptr){
        buffer = new Queue_el<T>;
        *buffer = *bufferq;
        buffer = buffer->pTailEl;
        bufferq = bufferq->pTailEl;

    }
    pTail = buffer;
}

template<typename T>
Queue<T>::~Queue() {
    if (pHead != nullptr) {
        Queue_el<T> *buffer1 = pHead;
        Queue_el<T> *buffer2 = pHead;
        while (buffer1->pTailEl != nullptr) {
            buffer1 = buffer1->pTailEl;
            delete buffer2;
            buffer2 = buffer1;
        }
        delete buffer1;
    }
}

template<typename T>
Queue<T>::Queue(Queue<T> &&q){ //move Konstruktor
    pHead = q.pHead;
    pTail = q.pTail;
    q.pHead = nullptr;
    q.pTail = nullptr;
}

template<typename T>
Queue<T>& Queue<T>::operator=(const Queue<T> &q) {
    if (this != &q) {
        if (pHead != nullptr) {     
            Queue_el<T> *buffer1 = pHead;
            Queue_el<T> *buffer2 = pHead;
            while (buffer1->pTailEl != nullptr) {
                buffer1 = buffer1->pTailEl;
                delete buffer2;
                buffer2 = buffer1;
            }
            delete buffer1;
            pHead = nullptr;
            pTail = nullptr;
        }

        if (q.pHead != nullptr) {   

            Queue_el<T> *buffer = pHead;
            Queue_el<T> *bufferq = q.pHead;

            do {
                buffer = new Queue_el<T>;
                *buffer = *bufferq;
                buffer = buffer->pTailEl;
                bufferq = bufferq->pTailEl;

            } while (bufferq->pTailEl != nullptr);
            pTail = buffer;

        }

    }
    return *this;
}

template<typename T>
Queue<T>& Queue<T>::operator=(Queue<T> &&q) { 
    if(this != &q){
    pHead = q.pHead;
    pTail = q.pTail;
    q.pHead = nullptr;
    q.pTail = nullptr;

    }
    return *this;
}

template<typename T>
void Queue<T>::push(T data) const {
    if (pTail != nullptr) {
        pTail->pTailEl = new Queue_el<T>;
        pTail->pTailEl->pHeadEl = pTail;
        pTail = pTail->pTailEl;
        *pTail = data;
    } else {                        
        pTail = new Queue_el<T>(data);
        pHead = pTail;
    }
    return;
}

template<typename T>
T Queue<T>::pop() const {
    if (pHead != nullptr) {
        if (pHead->pTailEl != nullptr) {
            Queue_el<T> *buffer = pHead;
            pHead = pHead->pTailEl;
            pHead->pHeadEl = nullptr;
            std::cout <<"Pop here: ";
            return buffer;
        } else {
            Queue_el<T> *buffer = pHead;
            delete pHead;
            pHead = nullptr;
            pTail = nullptr;
            return *buffer;
        }
    }
}

template<typename T>
bool Queue<T>::empty() const {
    if (pHead == nullptr) {
        return true;
    } else {
        return false;
    }
}

template<typename T>
int Queue<T>::size() const {
    int i = 0;
    if (pHead != nullptr) {
        Queue_el<T> *buffer = pHead;
        i++;
        while (buffer->pTailEl != nullptr) {
            buffer = buffer->pTailEl;
            i++;
        }
    }
    return i;
}

template<typename U>
std::ostream& operator<<(std::ostream& os, const Queue<U> &q){
    if(q.pHead != nullptr){
        Queue_el<U>* buffer = q.pHead;
        os << buffer << std::endl;          
        while(buffer->pTailEl != nullptr){  
            buffer = buffer->pTailEl;
            os << buffer << std::endl;
            };
    }
    return os;
}

template<> std::ostream& operator<< <std::string>
            (std::ostream& os, const Queue<std::string> &q);
template<> std::ostream& operator<< <double>
            (std::ostream& os, const Queue<double> &q);
template<> std::ostream& operator<< <int>
            (std::ostream& os, const Queue<int> &q);




template<typename T>
Queue_el<T>::Queue_el(Queue_el<T>* a, Queue_el<T>* b)
        :pHeadEl(a), pTailEl(b)
{

}

template<typename T>
Queue_el<T>::Queue_el(const Queue_el<T> &q)
{
    data = q.data;
    pHeadEl = nullptr;
    pTailEl = nullptr;
}

template<typename T>
Queue_el<T>::~Queue_el(){
    std::cout << "Element zerstört" << std::endl;
}

template<typename T>
Queue_el<T>& Queue_el<T>::operator=(Queue_el<T> q){
    data = q.data;
    return data;
}

template<typename U>
std::ostream& operator<<(std::ostream& os, const Queue_el<U> &q){
    os << q.data;
    return os;
}

template<>
std::ostream& operator<< <std::string> (std::ostream& os, const Queue_el<std::string> &q);
template<>
std::ostream& operator<< <double>(std::ostream& os, const Queue_el<double> &q);
template<>
std::ostream& operator<< <int>(std::ostream& os, const Queue_el<int> &q);

At the end of Queue.hpp , you have:Queue.hpp的末尾,您有:

template<> class Queue_el<std::string>;
template<> class Queue_el<double>;
template<> class Queue_el<int>;

template<> class Queue<std::string>;
template<> class Queue<double>;
template<> class Queue<int>;

All of these constructs declare template specializations of corresponding class templates Queue_el and Queue .所有这些构造都声明了相应类模板Queue_elQueue模板Queue_el

What you likely wanted is explicit template instantiation .您可能想要的是显式模板实例化 The difference in the syntax is that the latter is missing <> after template keyword:语法上的区别在于后者在template关键字之后缺少<>

template class Queue_el<std::string>;
template class Queue_el<double>;
template class Queue_el<int>;

template class Queue<std::string>;
template class Queue<double>;
template class Queue<int>;

However, note that this can be done only at a place where the template is fully defined.但是,请注意,这只能在完全定义模板的地方进行。 Therefore, you need to put it at the end of Queue.cpp , instead of at the end of Queue.hpp :因此,您需要将它放在Queue.cpp的末尾,而不是放在Queue.hpp

As remarked in the comments正如评论中所说

template<> class Queue<std::string>;

declares the full template specialization for T=std::string , but then does not provide the definition, hence Queue<std::string> is an incomplete type.声明了T=std::string的完整模板特化,但没有提供定义,因此Queue<std::string>是一个不完整的类型。

If you want to pre-compile the instantination Queue<std::string> then you should do the follow two things:如果你想预编译实例化Queue<std::string>那么你应该做以下件事:

  1. In file Queue.hpp at the end add the line在文件 Queue.hpp 最后添加一行

    extern template class Queue<std::string>;

    which tells the compiler that an instantiation exists elsewhere and prevents it from creating another one.它告诉编译器一个实例化存在于其他地方,并阻止它创建另一个实例化。

  2. In file Queue.cpp at the end add the line在文件 Queue.cpp 最后添加一行

    template class Queue<std::string>;

    which creates the actual instantiation promised by the extern statement in the header file.它创建了头文件中extern语句所承诺的实际实例化。

Moreover, it would make the design easier if the element type is a nested type within Queue<T> : then no separate explicit instantiation is needed.此外,如果元素类型是Queue<T>的嵌套类型,它会使设计更容易:那么不需要单独的显式实例化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM