【问题标题】:Redefinition error in ostream overload in template and inherited classes模板和继承类中的 ostream 重载重定义错误
【发布时间】:2015-02-27 11:21:11
【问题描述】:

我正在尝试在模板和继承类中重载 ostream 运算符,并且我一直在遵循一些提示 herehere,但我收到了重新定义错误。这是我的代码的复制:

#include <iostream>

enum type
{
        A,
        B
};

template <type T>
class base
{
protected:
        virtual std::ostream& print(std::ostream& out) const =0;
};

template <type T>
class derived: public base<T>
{
protected:
        virtual std::ostream& print(std::ostream& out) const
        {
                out<<"Hello World.\n";
                return out;
        }
public:
        template <type S>
        friend std::ostream& operator<<(std::ostream& out, const derived<S>& D)
        {
                return (D.print(out));
        }
};

int main ()
{
#ifdef __NOT_WORKING__
        derived<A> a;
        std::cout<<a;
        derived<B> b;
        std::cout<<b;
#else
        derived<A> a;
        std::cout<<a;
#endif
        return 0;
}

如果我只定义一个派生 A 类,一切正常,但如果我定义一个派生 A 和一个派生 B 类,我会从编译器收到此错误:

test.cpp: In instantiation of 'class derived<(type)1u>':
test.cpp:38:20:   required from here
test.cpp:27:30: error: redefinition of 'template<type S> std::ostream& operator<<(std::ostream&, const derived<S>&)'
         friend std::ostream& operator<<(std::ostream& out, const derived<S>& D)
                              ^
test.cpp:27:30: note: 'template<type S> std::ostream& operator<<(std::ostream&, const derived<S>&)' previously defined here
test.cpp: In instantiation of 'std::ostream& operator<<(std::ostream&, const derived<S>&) [with type S = (type)1u; type T = (type)0u; std::ostream = std::basic_ostream<char>]':
test.cpp:39:20:   required from here
test.cpp:20:31: error: 'std::ostream& derived<T>::print(std::ostream&) const [with type T = (type)1u; std::ostream = std::basic_ostream<char>]' is protected
         virtual std::ostream& print(std::ostream& out) const
                               ^
test.cpp:29:37: error: within this context
                 return (D.print(out));
                                     ^

为什么要重新定义好友功能? 感谢您的宝贵时间。

PS。我正在使用 gcc49。

【问题讨论】:

    标签: c++ templates inheritance ostream


    【解决方案1】:

    替换

    template <type S>
    friend std::ostream& operator<<(std::ostream& out, const derived<S>& D)
    {
        return (D.print(out));
    }
    

    friend std::ostream& operator<<(std::ostream& out, const derived<T>& D)
    {
        return (D.print(out));
    }
    

    错误会消失。

    使用较早的定义,您正在尝试定义具有相同签名的新模板函数。

    【讨论】:

      【解决方案2】:

      [temp.friend]/4:

      当函数在类的友元函数声明中定义时 模板,当函数被使用时,函数被实例化。 对多个声明和定义的相同限制 适用于非模板函数声明和定义也适用 这些隐含的定义。

      Clang 编译了上述罚款 - 这可以被认为是一个错误,但请记住,违反 ODR 是不正确的,不需要诊断。


      你有两种方法可以解决这个问题。提取模板的定义:

      template <typename T>
      class derived: public base<T>
      {
      //     [..]
      
             template <type S>
             friend std::ostream& operator<<(std::ostream& out, const derived<S>& D);
      };
      
      template <type S>
      std::ostream& operator<<(std::ostream& out, const derived<S>& D)
      {
          return (D.print(out));
      }
      

      或者将操作符设为非模板:

      template <type T>
      class derived: public base<T>
      {
      //     [..]
      
             friend std::ostream& operator<<(std::ostream& out, const derived<T>& D)
             {
                     return (D.print(out));
             }
      };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-12-14
        • 2020-02-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多