我正在尝试重载模板和继承类中的ostream运算符,我一直在关注一些提示here和here,但是我得到了重新定义错误。这是我的代码的再现:
#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。
答案 0 :(得分: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));
}
错误将消失。
使用早期定义,您尝试定义具有相同签名的新模板函数。
答案 1 :(得分:0)
[temp.friend] / 4:
在类中的友元函数声明中定义函数时 模板,当函数使用odr时,该函数被实例化。 对多个声明和定义的相同限制 适用于非模板函数的声明和定义也适用 这些隐含的定义。
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));
}
};