友元模板重载运算符 <<:未解析的外部符号

Rob*_*ook 3 c++ templates operator-overloading friend

我遇到了错误问题

错误 LNK2019 未解析的外部符号“class std::basic_ostream > & __cdecl cop4530::operator<<(class std::basic_ostream > &,class rob::Stack const &)”(??6rob@@YAAAV?$basic_ostream@DU ?$char_traits@D@std@@@std@@AAV12@ABV?$Stack@H@0@@Z) 在函数 _main Project7 c:\Users\Robrik\documents\visual studio 2015\Projects\Project7\Project7 中引用\post.obj 1

现在,post所做的就是调用operator<<

声明

namespace rob {     

template < typename T> class Stack {
    friend std::ostream& operator<< (std::ostream& os, const Stack<T>& a);
    void print(std::ostream& os, char ofc = ' ') const;
private:
    std::vector<T> arr;
};
Run Code Online (Sandbox Code Playgroud)

定义

template < typename T>
inline std::ostream & rob::operator<<(std::ostream & os, const Stack<T>& a)                {     
    return a.print(os, ' ');
}
template<typename T>
inline void rob::Stack<T>::print(std::ostream & os, char c) const
{
    for (int i = 0; i != arr.size(); i++)
    {
        os << c << arr[i];
    }
    os << '\n';
}
Run Code Online (Sandbox Code Playgroud)

它们分别位于.h文件和 a 中.hpp,我要求运算符不是成员函数(用于赋值)。

Nia*_*all 8

代码示例的问题;

template <typename T>
class Stack {
    friend std::ostream& operator<< (std::ostream& os, const Stack<T>& a);
    void print(std::ostream& os, char ofc = ' ') const;
    // ...
};
Run Code Online (Sandbox Code Playgroud)

是不是operator<<被声明为非模板函数。对于T与 一起使用的每种类型Stack,都需要有一个非模板operator<<。例如,如果Stack<int>声明了一个类型,那么必须有如下的运算符实现;

std::ostream& operator<< (std::ostream& os, const Stack<int>& a) {/*...*/}
Run Code Online (Sandbox Code Playgroud)

由于它没有实现,链接器无法找到它并导致您得到错误。

作为旁注;gcc 对此发出如下警告

warning: friend declaration 'std::ostream& operator<<(...)' declares a non-template function [-Wnon-template-friend]

note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)

这可能不是预期的,每个瞬间原子都有自己的实现。

要纠正此问题,您可以在Stack类型之前声明一个模板运算符,然后将实例化声明为友元。语法看起来有点笨拙,但看起来如下;

// forward declare the Stack
template <typename>
class Stack;

// forward declare the operator <<
template <typename T>
std::ostream& operator<<(std::ostream&, const Stack<T>&);

template <typename T>
class Stack {
    friend std::ostream& operator<< <>(std::ostream& os, const Stack<T>& a);
    // note the required <>        ^^^^
    void print(std::ostream& os, char ofc = ' ') const;
    // ...
};

template <typename T>
std::ostream& operator<<(std::ostream&, const Stack<T>&)
{
  // ... implement the operator
}
Run Code Online (Sandbox Code Playgroud)

上面的代码将算子的友谊限制在对应的实例化Stack,即operator<< <int>实例化仅限于访问实例化的私有成员Stack<int>

替代方案包括允许友谊扩展到模板的所有实例;

template <typename T>
class Stack {
    template <typename T1>
    friend std::ostream& operator<<(std::ostream& os, const Stack<T1>& a);
    // ...
};
Run Code Online (Sandbox Code Playgroud)

operator<<然后可以在类定义内部或外部内联完成的实现。