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

为什么不可能覆盖涉及第三方代码的模板类的operator<<呢?

  •  6
  • Mohan  · 技术社区  · 7 年前

    我问了以下问题 https://stackoverflow.com/a/51951315/1908650 :

    我想超载 template<class T> ostream& operator<<(ostream& os, const optional<unique_ptr<T>>& )

    在评论中,@yakk-adam nevraumont指出:

    这个问题的答案是“你不能”。对于一个通用类型T来说,没有一个好的法律方法可以做到这一点;我可以解释为什么,但要做到这一点需要一个新的问题/答案。

    我正在创建一个新的Q.来接受这类提议…

    2 回复  |  直到 7 年前
        1
  •  8
  •   Yakk - Adam Nevraumont    7 年前

    在与类型关联的命名空间中重载运算符的正确位置。

    为了 std::optional<std::unique_ptr<T>> 有一个关联的命名空间 std 总是在那里(从 ostream optional unique_ptr )以及与之关联的任何命名空间 T . 当您希望为所有类型重载时,与 T 对你没用。

    将新功能或重载引入 性病 ;在某些有限的情况下,您可以引入专门化,但这里没有适用的专门化。添加新的重载 << 性病 使程序格式错误,不需要诊断。

    你可以用装饰的 尤尼奎 可选择的 从您自己的名称空间,或(b)使用装饰 溪流 或(c)编写格式化程序包装:

    namespace fmt {
      template<class T>
      struct wrapper_t {
        T&& t;
      };
      template<class T>
      struct is_wrapped:std::false_type{};
      template<class T>
      struct is_wrapped<wrapper_t<T>>:std::true_type{};
    
      template<class OS, class T,
        std::enable_if_t<!is_wrapped<OS&>{}, bool> =true
      >
      auto operator<<( OS& os, wrapper_t<T>&& w )
      -> decltype( os << std::forward<T>(w.t) )
          { return os << std::forward<T>(w.t); }
      template<class OS, class T>
      auto operator<<( wrapper_t<OS&> os, T&& t )
      -> decltype( os.t << std::forward<T>(t) )
          { return os.t << std::forward<T>(t); }
    
      template<class T>
      wrapper_t<T> wrap(T&& t){ return {std::forward<T>(t)}; }
    }
    

    然后 std::cout << fmt::wrap( foo ) 无法找到的重载 << 在内部 fmt ,如果找不到,则调用 << 在包含的数据上。

    这也支持 fmt::wrap(std::cout) 而不是包装参数。可能有打字错误。

        2
  •  0
  •   Chris Uzdavinis    7 年前

    除上述内容外,还有一个涉及ODR问题的问题。如果您为您不控制的类型重载一个函数,可以想象其他人也以不同的方式重载它。然后你用你的重载编译你的代码,他们用重载编译他们的代码,当你为同一家公司工作时,你会得到不同翻译单元中相同签名函数的多个版本。同样,未定义的行为,不需要诊断。

    消毒剂可能会发现这一点,也许听起来是人为的,但这种事情时常发生。