[英]operator<<(ostream&, X) for class X nested in a class 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;
}
这个不能编译(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;
}
错误消息如下所示:
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’
在 0x 模式下,第二条错误信息不同,但含义相同。
有可能做我想做的事吗?
编辑显然,这里有一个非推断上下文的实例,它解释了错误消息。 然而,问题仍然存在:对于嵌套在 class 模板中的 class,我可以有一个工作operator<<
吗?
这是函数的一般问题:
template <typename C>
void func(typename C::iterator i);
现在,如果我调用func(int*)
,我应该使用C
的哪个值?
一般来说,你不能向后工作! 许多不同的C
可能已经定义了一个内部类型iterator
,该迭代器恰好是某些参数集的int*
。
在你的情况下,你的情况有点复杂:
template <typename T>
void func(typename Z<T>::ZZ const&);
但基本上这是同一个问题, Z<T>
是一个模板,而不是完整的 class,并且您要求为此模板的内部类型ZZ
创建一个 function。
假设我这样做:
template <typename T>
struct Z { typedef T ZZ; };
template <typename T>
struct Z<T const> { typedef T ZZ; };
注意:典型的迭代器, value_type
不是 const 限定的
那么,在调用func(int)
时,我应该使用Z<int>
还是Z<int const>
?
它是不可扣除的。
因此整个事情被称为不可演绎的上下文,标准禁止它,因为没有明智的答案。
经验法则:怀疑 function 参数中的typename
。
注意:如果另一个参数已经确定了类型,它们是可以的,例如typename C::iterator find(C&, typename C::const_reference);
因为一旦推导出C
,那么C::const_reference
可以毫无问题地使用
除了友元声明与操作符模板不匹配的问题(或许可以修复为)
class ZZ {
template<class U>
friend std::ostream& operator<<(std::ostream& os, const ZZ&);
};
你也有一个“非推断上下文”的问题,这是马蒂厄所链接的。
在这个模板中
template<typename T>
std::ostream& operator<< (std::ostream& os, const typename Z<T>::ZZ&) {
return (os << "ZZ!");
}
编译器无法确定 T's you 参数将匹配的内容。 如果您专注于某些类型,可能会有多个匹配项
template<>
class Z<long>
{
public:
typedef double ZZ;
};
template<>
class Z<bool>
{
public:
typedef double ZZ;
};
现在,如果我尝试打印double
, T
可能是bool
或long
。
如果不检查所有可能的 T,编译器就无法确定这一点,而且它不必这样做。 它只是跳过您的运营商。
Matthieu 很好地解释了这个问题,但在这种情况下可以使用一个简单的解决方法。 您可以使用朋友声明在 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;
}
一种不同的技术是提供一个外行的 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!");
}
不过最好使用朋友 function 定义。 但很高兴了解替代方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.