为什么不运营商<<在main中获取派生类的重载?
#include <iostream>
struct Base {};
std::ostream& operator<<(std::ostream& os, const Base&) { return os << "Hi\n"; }
template <class T>
struct Container
{
class Derived : Base {
template <class U>
friend std::ostream& operator<<(std::ostream& os, const typename Container<U>::Derived&);
};
};
template <class U>
std::ostream&
operator<<(std::ostream& os, const typename Container<U>::Derived& der)
{
return os << static_cast<const Base&>(der);
}
int main()
{
Container<int>::Derived d;
std::cout << d;
return 0;
}
g ++说:
/tmp $ g++ test.c
test.c: In function ‘int main()’:
test.c:28: error: ‘Base’ is an inaccessible base of ‘Container<int>::Derived’
/tmp $
编辑:私有继承是故意的。这就是为什么运营商&lt;&lt;宣布为朋友&#39;。
EDIT2 :朋友声明的固定位置;在内部阶级。
答案 0 :(得分:3)
在你的:
template <class U>
std::ostream&
operator<<(std::ostream& os, const typename Container<U>::Derived& der)
第二个参数中的U
位于非推导的上下文中(请参阅
§14.8.2.5/ 5),所以编译器在找不到这个函数的时候
在operator<<
上执行运算符重载决策
main
。因此,没有此功能的实例化
在重载集和重载决策(总是
忽略访问问题)选择非模板operator<<
取Base const&
。访问控制然后导致错误
你看到了。
有几种解决方案。可能最简单的是不
声明operator<<
Derived
作为模板,但是
在Derived
:
friend std::ostream& operator<<( std::ostream& dest, Derived const& obj )
{
return os << static_cast<Base const&>( obj );
}
这是如何工作的有点棘手。你要宣告的朋友
是不是模板;有一个单独的非模板功能
对于Container
的每个实例化。如果它不是内联的,
你必须提供一个单独的,非模板化的实现
对于每种类型。但由于它是内联的,编译器提供它
为了你。虽然没有注入函数的名称
在周围环境中,它将由ADL发现。
当然,由于这个operator<<
不是模板,所以有
找不到任何参数推论。