繁体   English   中英

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

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

这是我第一次遇到无法通过简单的谷歌搜索解决的问题。 我在 C++ 中的作业分配有问题。 作为 Startup,我们不允许更改 main.cpp。 任务是,编写一个双链表并使用模板类。

我得到了错误

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

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

如果我用谷歌搜索这些错误,答案是我可能没有在头文件或类似的声明或定义错误中正确声明我的类。 但是我找不到我犯的错误。

我用构造函数尝试了不同的方法(有和没有初始化列表)。 我尝试了特殊化。 如果我将友元运算符<< 的特殊化放在头文件中(我认为总是这样做),我会收到此错误:

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

我希望你能帮助我。

这是不应更改的 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;
}

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_ */

和 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);

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>;

所有这些构造都声明了相应类模板Queue_elQueue模板Queue_el

您可能想要的是显式模板实例化 语法上的区别在于后者在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>;

但是,请注意,这只能在完全定义模板的地方进行。 因此,您需要将它放在Queue.cpp的末尾,而不是放在Queue.hpp

正如评论中所说

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

声明了T=std::string的完整模板特化,但没有提供定义,因此Queue<std::string>是一个不完整的类型。

如果你想预编译实例化Queue<std::string>那么你应该做以下件事:

  1. 在文件 Queue.hpp 最后添加一行

    extern template class Queue<std::string>;

    它告诉编译器一个实例化存在于其他地方,并阻止它创建另一个实例化。

  2. 在文件 Queue.cpp 最后添加一行

    template class Queue<std::string>;

    它创建了头文件中extern语句所承诺的实际实例化。

此外,如果元素类型是Queue<T>的嵌套类型,它会使设计更容易:那么不需要单独的显式实例化。

暂无
暂无

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

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