代码之家  ›  专栏  ›  技术社区  ›  KorbenDose

运算符的两阶段查找<<

  •  3
  • KorbenDose  · 技术社区  · 6 年前

    << 我正在上的课。出于某种原因,我将它分成两个函数,并从另一个函数调用一个函数。切换到模板后,它不再工作。在查找问题之后,我发现 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());
    }
    

    现在,这可以说不是很美,在我看来,抹去了 << 接线员。

    除了不拆分两个运算符的明显解决方案之外,有没有人对此有一个好的解决方案?

    1 回复  |  直到 6 年前
        1
  •  5
  •   SergeyA    6 年前

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

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

    至于如何解决这个问题-尽量不要对流使用非推导类型。如果不能,则流插入运算符可能不适合此操作,因为语法非常难看。只需使用正常功能。