不可见的算子<<内部过载

时间:2014-08-06 18:12:25

标签: c++

为什么不运营商<<在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 :朋友声明的固定位置;在内部阶级。

1 个答案:

答案 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<<不是模板,所以有 找不到任何参数推论。