首页 > 解决方案 > 为什么不能为涉及第三方代码的模板类覆盖 operator<<?

问题描述

我在https://stackoverflow.com/a/51951315/1908650中询问了以下内容 :

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

在评论中,@Yakk - Adam Nevraumont 指出:

这个问题的答案是“你不能”。对于泛型类型 T,没有好的合法方法可以做到这一点;我可以解释原因,但这样做需要一个新的问题/答案

我正在创建一个新的 Q. 来接受好心的提议...

标签: c++overloading

解决方案


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

因为std::optional<std::unique_ptr<T>>有一个std始终存在的关联命名空间(来自ostreamandoptionalunique_ptr),再加上与 . 关联的任何命名空间T。由于您想为所有类型重载,因此关联的命名空间T对您没有用处。

在 ;中引入新函数或重载是不合法的std。在某些有限的情况下,您可以引入专业化,但它们都不适用于这里。添加新的重载<<tostd会使您的程序格式错误,无需诊断。

您可以 (A) 使用您自己的命名空间中的 decorated unique_ptror optionals,或者 (B) 使用 decorated ostream,或者 (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)}; }
}

then可以找到withinstd::cout << fmt::wrap( foo )的重载,如果没有找到则调用包含的数据。<<fmt<<

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


推荐阅读