运营商的两阶段查找<<

时间:2018-05-30 14:19:05

标签: c++ templates

目前我正在尝试为我正在处理的类重载插入运算符<<。出于某种原因,我将其分成两个函数,并从另一个函数中调用一个函数。切换到模板后,它不再起作用了。在查找问题后,我发现背后有two stage lookupsome 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());
}

现在这可能不是很漂亮,我认为这会消除<<运营商的目的。

除了不拆分这两个操作符的明显解决方案之外,有没有人有一个很好的解决方案呢?

1 个答案:

答案 0 :(得分:5)

您所描述的问题与两步查找无关。相反,它与函数

中的事实有关
template <typename Foo, typename Bar>
std::ostream& operator<<(std::ostream& out, const typename MyClass<Foo,Bar>::bar_t& bar)

FooBar位于非推断的上下文中。这意味着,每次调用函数时都必须提供这些模板参数。

虽然编译器不能在这里推断类型,但让我们考虑一个不起作用的同一个更简单的例子:

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编译器可以推断出来。

至于如何解决这个问题 - 尽量不要在流中使用非推导类型。如果你不能,可能流插入操作符不适合这个,因为语法真的很难看。只需使用普通功能。