目前我正在尝试为我正在处理的类重载插入运算符<<
。出于某种原因,我将其分成两个函数,并从另一个函数中调用一个函数。切换到模板后,它不再起作用了。在查找问题后,我发现背后有two stage lookup和some reasoning。
基本上,我试图做的是以下内容:
template <typename Foo, typename Bar>
class MyClass {
public:
using foo_t = Foo;
using bar_t = Bar;
bar_t some_func() const { /* do something */ }
};
/* Level 2 operator */
template <typename Foo, typename Bar>
std::ostream& operator<<(std::ostream& out, const typename MyClass<Foo,Bar>::bar_t& bar) {
return out << some_other_func(bar);
}
/* Level 1 operator calls level 2 operator */
template <typename Foo, typename Bar>
std::ostream& operator<<(std::ostream& out, const MyClass<Foo,Bar>& myClass) {
return out << myClass.some_func();
}
不幸的是,由于bar_t
依赖的事实,这不会编译我将1级操作符更改为以下内容:
template <typename Foo, typename Bar>
std::ostream& operator<<(std::ostream& out, const MyClass<Foo,Bar>& myClass) {
return operator<<<Foo,Bar>(out,myClass.some_func());
}
现在这可能不是很漂亮,我认为这会消除<<
运营商的目的。
除了不拆分这两个操作符的明显解决方案之外,有没有人有一个很好的解决方案呢?
答案 0 :(得分:5)
您所描述的问题与两步查找无关。相反,它与函数
中的事实有关template <typename Foo, typename Bar>
std::ostream& operator<<(std::ostream& out, const typename MyClass<Foo,Bar>::bar_t& bar)
Foo
和Bar
位于非推断的上下文中。这意味着,每次调用函数时都必须提供这些模板参数。
虽然编译器不能在这里推断类型,但让我们考虑一个不起作用的同一个更简单的例子:
template<class T> struct A {
using type = int;
type i = 42;
};
template<class T> void foo(typename A<T>::type );
...
A<void*> a;
foo(a.i); // problematic call
您希望在上面的示例中将T
推断为void*
。但是,a.i
的类型是int。因此该呼叫与
foo(int(42));
显然,这里没有有意义的T
编译器可以推断出来。
至于如何解决这个问题 - 尽量不要在流中使用非推导类型。如果你不能,可能流插入操作符不适合这个,因为语法真的很难看。只需使用普通功能。