如何为成员类型的模板重载自由函数

时间:2013-03-14 14:37:07

标签: c++ templates overloading c++03

我有一个定义某些成员类型的模板类。它与std::map基于它自己的模板参数定义value_type的方式类似,但在我的情况下,类型更复杂,因此它被定义为嵌套类。

现在进行调试我想为该类型定义operator<<。但是编译器告诉我它不能推断出外模板的模板参数。

我的真实代码并不像下面的例子那样做,但是这个人为的例子展示了我尝试的方法以及它如何失败:

#include <iostream>

template <typename Value> class Outer;

template <typename Value>
std::ostream &operator<<(std::ostream &, const typename Outer<Value>::Inner &);

template <typename Value>
class Outer {
  public:
    struct Inner {
    Value x;
    };

    void PrintSomething(Value v) {
    // the real program does something useful with the inner class, of course
    Inner inner = { v };
    std::cout << "Inner = " << inner << std::endl; // <---- THIS SAYS IT CAN'T FIND operator<<
    };
};

template <typename Value>
std::ostream &operator<<(std::ostream &s, const typename Outer<Value>::Inner &v) {
    return s << v.x;
}

int main() {
    Outer<int> o;
    o.PrintSomething(42);
    return 0;
}

这是重现问题的完整示例。编译器(我已经尝试了其中的3个)说没有operator<<的重载会采用类型Outer<int>::Inner的第二个参数。当我尝试使用不具有其他重载的不同函数的相同的东西时,它代替C2783: could not deduce template argument for 'identifier',gcc和clang继续说没有重载需要第二个参数Outer<int>::Inner)。

有没有办法定义operator<<为任何Outer<Value>::Inner定义Value,因为它是正确的(所以它不能被定义为成员)参数?

注意:我需要它在几个编译器中编译,其中一些没有任何C ++ 11特性,所以我需要它是C ++ 03。

1 个答案:

答案 0 :(得分:6)

你所拥有的是所谓的不可导出的上下文。怎么可以推断出Value?你可以部分地专门化类模板,使得编译器甚至不可能尝试测试每个可能的实例化(其中有......好,无限)。

有两种解决方法:从Inner中取出Outer,或使operator<<成为内联好友。后者是人们常去的方式。

template<class T>
struct Outer{
  struct Inner{
    T value;
    friend std::ostream& operator<<(std::ostream& os, Inner const& v){
      return os << v.value:
    }
  };
  // ...
};