首页 文章

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

提问于
浏览
2

我遇到了错误的问题

错误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;
};

定义

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

    你还应该在它实际所属的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){
        ...
    }
    
  • 1

    代码示例的问题;

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

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

    由于未实现,链接器无法找到它并导致您获得的错误 .

    作为旁注; gcc警告如下

    警告:朋友声明'std :: ostream&operator <<(...)'声明一个非模板函数[-Wnon-template-friend]注意:(如果这不是你想要的,请确保函数模板有已经声明并在函数名后添加<>)

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

    要更正此问题,您可以在 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<< 的实现 .

  • 2

    除了@ 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, ' ');
            }
       };
    
    }
    

相关问题