未解决的外部链接问题

unresolved externals- linking issues

目前正在学习 C++ 课程,获得了一个关于模板 classes 和函数的项目- 收到此错误消息,无法确定来自何处,所有文件都可以正常编译。 仔细检查所有声明等

错误消息: Menu.obj : error LNK2019: 未解析的外部符号 "class std::basic_ostream & __cdecl operator<<(class std::basic_ostream &,class CSet const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@ std@@@std@@AAV01@ABV?$CSet@J@@@Z) 在函数“private: bool __thiscall Menu::check(void)”中引用 (?check@Menu@@AAE_NXZ)

代码: CSET // 类型 t 的集合,头文件

#ifndef __C_SET_H__
#define __C_SET_H__
#include <iostream>
using namespace std;

template <class T>
class CSet
{
public:
    CSet() { m_length = 0; m_setArr = NULL; }//ctor
    CSet(const CSet& set);//cctor
    ~CSet() { delete[] m_setArr; }

    //--operators--//
    CSet& operator=(const CSet& );
    CSet& operator+=(const T& );
    CSet& operator-=(const T& );
     CSet& operator-(const CSet& )const;

    friend ostream& operator<<(ostream&, const CSet& );//ouput

    //--methods--//
    const CSet UNION(const CSet& );
    const CSet INTERSECT(const CSet& );

private:
    int m_length;
    T* m_setArr;

     int appears(const T& );//private method check index of T in setArr


};



template <class T>
CSet<T>::CSet(const CSet& set)//cctor
{
    *this = set;
}

template <class T>
CSet<T>& CSet<T>::operator=(const CSet& set)
{
    m_length = set.m_length;
    m_setArr = set.m_setArr;
    return *this;
}

template <class T>
CSet<T>& CSet<T>::operator+=(const T& val)
{
    if (appears(val) == -1)
        return *this;
    try
    {
        T* arr = new T[m_length + 1];
        for (int i = 0; i < m_length; i++)
            arr[i] = m_setArr[i];
        arr[m_length] = val;
        m_length++;
        delete[] m_setArr;
        m_setArr = arr;
        return *this;
    }
    catch (bad_alloc)
    {
        cout << "Memory Allocation Failed!" << endl;
        return *this;
    }
    
}

template <class T>
CSet<T>& CSet<T>::operator-=(const T& val)
{
    int index = appears(val);
    if (index == -1)
        return *this;
    m_length--;
    try
    {
        T* arr = new T[m_length];
        int j = 0;//index
        for (int i = 0; i < m_length; i++)
        {
            if (i == index)
                continue;
            arr[j] = m_setArr[i];
            j++;
        }
        delete[] m_setArr;
        m_setArr = arr;
        return *this;
    }
    catch (bad_alloc)
    {
        cout << "Memory Allocation Failed!" << endl;
        return *this;
    }
}

template <class T>
 CSet<T>& CSet<T>::operator-(const CSet& set)const
{

    CSet copy;
    copy.m_length = m_length;
    copy.m_setArr=m_setArr;
    copy.INTERSECT(set);
    CSet copy2=set;
    for (int i = 0; i < copy.m_length; i++)
        copy2.operator-=(copy.m_setArr[i]);
    return copy2;
}

template <class T>
ostream& operator<<(ostream& os, const CSet<T>& set)
{
    if (set.m_length == 0)
        os << "The set is empty!" << endl;
    else{
        os << '(';
        int i;
        for (i = 0; i < set.m_length - 1; i++)
            os << set.m_setArr[i] << ',';
        os << set.m_setArr[i] << ')' << endl;
    }
    return os;
}

template <class T>
const CSet<T> CSet<T>::UNION(const CSet& set)
{
    CSet copy;
    copy.m_length = m_length;
    copy.m_setArr = m_setArr;
    for (int i = 0; i < set.m_length; i++)
        copy.operator+=(set.m_setArr[i]);
    return copy;
}

template <class T>
const CSet<T> CSet<T>::INTERSECT(const CSet& set)//private
{
    CSet copy;
    copy.m_length = m_length;
    copy.m_setArr = m_setArr;
    for (int i = 0; i < set.m_length; i++)
        copy.operator-=(set.m_setArr[i]);
    return copy;
}

template <class T>
 int CSet<T>::appears(const T& val)//private
{
    for (int i = 0; i < m_length; i++)
        if (m_setArr[i] == val)
            return i;
    return -1;

}

#endif

MENU//打印并显示集合菜单 H 文件

#ifndef __MENU_H__
#define __MENU_H__
#include"CSet.h"
#include <iostream>
using namespace std;
class Menu
{
public:
    Menu();//prints menu
private:
    //--members--//
    CSet<long> longSet;
    CSet<char> chSet1;
    CSet<char> chSet2;
    CSet<string> strSet;
    //--methods--//
    bool check();
    void printSetsOp();
    void addRemoveElement(bool);
    void difference();

};
#endif

MENU.CPP

#include "Menu.h"
#include "CSet.h"
#include <iostream>
using namespace std;

Menu::Menu()
{//menu print
    do {
        //show the menu until the user wants to exit
        cout << "================MENU================" << endl;
        ...
    } while (check());//as long as the user doesnt want to exit
}

bool Menu::check()
{
    int choice;
    cin >> choice;//user input
    switch (choice)
    {
    case 1:
    {
        ...
        return true;//keep the menu loop going
    }
    .
    .
    .
    case 7:
    {//exit
        cout << "Goodbye!" << endl;
        return false;//exit the program
    }
    default:
    {//invalid number
        cout << "please enter a valid number!" << endl;
        return true;//keep the menu loop going
    }
    }
}

void Menu::printSetsOp()
{
    //print options
}

void Menu::addRemoveElement(bool add)
{
    printSetsOp();//print scnd menu
    int choice;
    cin >> choice;//which set
    switch (choice)
    {
    case 1:
    {//add or remove elements, each type seperatly
        long elm;
        cout << "Insert number =  ";
        cin >> elm;
        add ? longSet.operator+=(elm) : longSet.operator-=(elm);
        return;
    }
    case 2:
    case 3:
    {
        char ch;
        cout << "Insert character =  ";
        cin >> ch;
        if (add)
            (choice == 2) ? chSet1.operator+=(ch) : chSet2.operator+=(ch);
        else
            (choice == 2) ? chSet1.operator-=(ch) : chSet2.operator-=(ch);
        return;
    }
    default:
    {//invalid number
        cout << "please enter a valid number!" << endl;
        return;//keep the menu loop going
    }
    }
}

不知道是什么原因导致此错误,所以几乎所有内容都已发布。 谢谢

问题是您 CSet 的朋友 operator<< 命名的函数与您的模板 operator<< 不同。这实际上声明了一个新的 non-template 函数,它最终成为比模板函数更好的候选者,但是没有定义这样的函数,因此出现链接错误。

您可以通过使友元声明引用此运算符针对特定 CSet<T> 的完全特化来解决此问题。为此,必须已经声明模板函数,这需要 CSet 的前向声明。所以,你会做这样的事情:

template <class T> class CSet;

template <class T>
ostream& operator<<(ostream& os, const CSet<T>& set)
{
    // implementation here
}

template <class T>
class CSet {
    // all of your other stuff...

    // Add <> to have the friend declaration refer to a specific operator<< instantiation
    // With <>, T is deduced. You can also say <T> instead.
    friend ostream& operator<< <>(ostream&, const CSet& );
};

请注意,当您在模板类型中声明非模板友元函数时,大多数编译器应该警告您,因为它会导致您遇到的问题。确保您的编译器警告已启用。

warning: friend declaration 'std::ostream& operator<<(std::ostream&, const foo<T>&)' declares a non-template function