朋友模板重载运算符<&lt ;:未解析的外部符号

时间:2016-03-05 20:57:42

标签: 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 \视觉工作室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;
};

定义

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

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

3 个答案:

答案 0 :(得分:3)

代码示例的问题;

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

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

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

由于未实现,链接器无法找到它并导致错误。

作为旁注; 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
}

上面的代码限制了运算符与Stack的相应实例化的友谊,即operator<< <int>实例化仅限于访问Stack<int>实例化的私有成员。

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

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

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

答案 1 :(得分:1)

你还应该在它真正属于的rob命名空间内声明函数签名:

namespace rob {
template <typename T>
class Stack {
    friend std::ostream& operator<< (std::ostream& os, const Stack<T>& a);
};

template < typename T>
std::ostream& operator<< (std::ostream& os, const Stack<T>& a){
    ...
}

答案 2 :(得分:0)

除了@ LibertyPaul的回答,您需要向朋友template<T>行添加std::os...,以便工作:

namespace rob {

   template <typename T> class Stack {
        friend std::ostream& operator<< (std::ostream& os, const Stack<T>& a) {
              return a.arr.print(os, ' ');
        }
   };

}