简体   繁体   English

operator<<(ostream&, X) for class X 嵌套在 class 模板中

[英]operator<<(ostream&, X) for class X nested in a class template

This one compiles and works like it should (non-nested template):这个编译和工作就像它应该(非嵌套模板):

#include <iostream>

template<typename T> class Z;

template <typename T> 
std::ostream& operator<< (std::ostream& os, const Z<T>&) {
    return (os << "Z");
}

template<typename T> class Z {
    friend std::ostream& operator<< <> (std::ostream& os, const Z&);
};

int main () {
    Z<int> z;
    std::cout << z << std::endl;
}

This one doesn't compile (gcc 4.4 and gcc 4.6, in both 03 and 0x mode):这个不能编译(gcc 4.4 和 gcc 4.6,在 03 和 0x 模式下):

#include <iostream>

template<typename T> class Z;

template<typename T> 
std::ostream& operator<< (std::ostream& os, const typename Z<T>::ZZ&) {
    return (os << "ZZ!");
}

template <typename T> class Z {
  public:
    class ZZ {
        friend std::ostream& operator<< <> (std::ostream& os, const ZZ&);
    };
};


int main () {
    Z<int>::ZZ zz;
    std::cout << zz << std::endl;
}

The error message looks like this:错误消息如下所示:

error: template-id ‘operator<< <>’ for ‘std::ostream& operator<<(std::ostream&,
const Z<int>::ZZ&)’ does not match any template declaration
error: no match for ‘operator<<’ in ‘std::cout << zz’

In the 0x mode the second error message is different, but the meaning is the same.在 0x 模式下,第二条错误信息不同,但含义相同。

Is it possible to do what I want to do?有可能做我想做的事吗?

EDIT Apparently, there's an instance of non-deduced context here, which explains the error messages.编辑显然,这里有一个非推断上下文的实例,它解释了错误消息。 The question, however, still stands: can I have a working operator<< for a class nested in a class template?然而,问题仍然存在:对于嵌套在 class 模板中的 class,我可以有一个工作operator<<吗?

This is a general problem for functions:这是函数的一般问题:

template <typename C>
void func(typename C::iterator i);

Now, if I call func(int*) , which value of C should I use?现在,如果我调用func(int*) ,我应该使用C的哪个值?

In general, you cannot work backward !一般来说,你不能向后工作! Many different C could have defined an internal type iterator that happens to be a int* for some set of parameters.许多不同的C可能已经定义了一个内部类型iterator ,该迭代器恰好是某些参数集的int*

In your case, you are complicating the situation a bit:在你的情况下,你的情况有点复杂:

template <typename T>
void func(typename Z<T>::ZZ const&);

But fundamentally this is the same issue, Z<T> is a template, not a full class, and you are asking to create a function for the inner type ZZ of this template.但基本上这是同一个问题, Z<T>是一个模板,而不是完整的 class,并且您要求为此模板的内部类型ZZ创建一个 function。

Suppose I do:假设我这样做:

template <typename T>
struct Z { typedef T ZZ; };

template <typename T>
struct Z<T const> { typedef T ZZ; };

Note: typical of iterators, the value_type is not const-qualified注意:典型的迭代器, value_type不是 const 限定的

Then, when invoking func(int) , should I use Z<int> or Z<int const> ?那么,在调用func(int)时,我应该使用Z<int>还是Z<int const>

It is non-deducible.它是不可扣除的。

And thus the whole thing is referred to as a non-deducible context , and the Standard forbids it because there is no sensible answer.因此整个事情被称为不可演绎的上下文,标准禁止它,因为没有明智的答案。

Rule of Thumb: be suspicious of typename in the parameters of a function.经验法则:怀疑 function 参数中的typename

Note: they are OK if another argument already pinned down the type, example typename C::iterator find(C&, typename C::const_reference);注意:如果另一个参数已经确定了类型,它们是可以的,例如typename C::iterator find(C&, typename C::const_reference); because once C is deduced, then C::const_reference may be used without trouble因为一旦推导出C ,那么C::const_reference可以毫无问题地使用

Apart from the problem that the friend declaration doesn't match the operator template (perhaps fixable as)除了友元声明与操作符模板不匹配的问题(或许可以修复为)

class ZZ {
    template<class U>
    friend std::ostream& operator<<(std::ostream& os, const ZZ&);
};

you also have a problem with a "non-deduced context", which is what Matthieu links to.你也有一个“非推断上下文”的问题,这是马蒂厄所链接的。

In this template在这个模板中

template<typename T> 
std::ostream& operator<< (std::ostream& os, const typename Z<T>::ZZ&) {
    return (os << "ZZ!");
}

the compiler isn't able to figure out for what T's you parameter will match.编译器无法确定 T's you 参数将匹配的内容。 There could be several matches, if you specialize for some types如果您专注于某些类型,可能会有多个匹配项

template<>
class Z<long>
{
public:
    typedef double   ZZ;
};

template<>
class Z<bool>
{
 public:
    typedef double   ZZ;
};

Now if I try to print a double , T could be either bool or long .现在,如果我尝试打印doubleT可能是boollong

The compiler cannot know this for sure without checking for all possible T's, and it doesn't have to do that.如果不检查所有可能的 T,编译器就无法确定这一点,而且它不必这样做。 It just skips your operator instead.它只是跳过您的运营商。

Matthieu explained the problem very well, but a simple work-around can be used in this case. Matthieu 很好地解释了这个问题,但在这种情况下可以使用一个简单的解决方法。 You can implement the friend function inside the class with the friend declaration:您可以使用朋友声明在 class 中实现朋友 function :

#include <iostream>

template <typename T> class Z {
public:
  class ZZ {
    friend std::ostream& operator<< (std::ostream& os, const ZZ&) {
      return os << "ZZ!";
    }
  };
};


int main () {
  Z<int>::ZZ zz;
  std::cout << zz << std::endl;
}

A different technique is to provide an out of line class template which works like a hook.一种不同的技术是提供一个外行的 class 模板,它像一个钩子一样工作。

template <typename T> class ZZZ { 
  T &getDerived() { return static_cast<T&>(*this); }
  T const &getDerived() const { return static_cast<T const&>(*this); }

protected:
  ~ZZZ() { }
};

template <typename T> class Z {
  public:
    class ZZ : public ZZZ<ZZ> {
    };
};

template<typename ZZ> 
std::ostream& operator<< (std::ostream& os, const ZZZ<ZZ> &zzz) {
    ZZ const& zz = zzz.getDerived();
    /* now you can use zz */
    return (os << "ZZ!");
}

Using a friend function definition is preferable though.不过最好使用朋友 function 定义。 But it's good to know about alternatives.但很高兴了解替代方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 operator &lt;&lt;(ostream&os,...)用于模板类 - operator<<(ostream& os, …) for template class 动态数组模板类:ostream和操作员好友功能问题 - Dynamic Array Template Class: problem with ostream& operator friend function 未定义对 `operator&lt;&lt;(std::ostream&amp;, /* class 与非类型模板参数 */&amp;)' 的引用 - undefined reference to `operator<<(std::ostream&, /* class with non-type template parameters */&)' 重载运算符&lt;&lt;(ostream&,T),其中T是“枚举类MyEnum” - Overloading operator<<(ostream&, T) where T is “enum class MyEnum” ostream&运算符&lt;&lt;(ostream&(* pf)(ostream&)); - ostream& operator<< (ostream& (*pf)(ostream&)); “覆盖” ostream&运算符&lt; - “Overriding” ostream& operator << 在没有static_cast &lt;&gt;的派生类中重载std :: ostream&operator &lt;&lt; - overloading std::ostream& operator<< in the derived class without static_cast<> 什么是在类名后使用的&符号,如ostream&operator <<(...)? - What's the ampersand for when used after class name like ostream& operator <<(…)? 朋友 std::ostream&amp; operator&lt;&lt; 声明不允许我访问类的私有成员 - friend std::ostream& operator<< declaration doesn't let me access the class' private members 是否有隐式模板 <typename T> 运算符&lt;&lt;(const ostream&,T)? - Is there an implicit template<typename T>operator<<(const ostream&,T)?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM