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

Moh*_*han 6 c++ overloading

我在/sf/answers/3636592081/中询问了以下内容 :

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

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

这个问题的答案是"你做不到".对于通用类型T,没有合法的方法可以做到这一点; 我可以解释原因,但这样做会有新的问题/答案

我正在创造一个新的Q.以接受这种报价......

Yak*_*ont 8

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

对于std::optional<std::unique_ptr<T>>有一个关联的命名空间std是永远存在的(从ostreamoptionalunique_ptr),加上无论命名空间相关联T.由于您希望为所有类型重载,因此与之关联的命名空间T对您无用.

引入新功能或过载是不合法的std; 在某些有限的情况下,您可以引入专业化,但这些都不适用于此.添加一个新的过载<<,以std使你的程序生病形成,没有诊断需要.

您可以(A)使用自己的命名空间中的deco unique_ptroptionals,或(B)使用装饰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)}; }
}
Run Code Online (Sandbox Code Playgroud)

然后std::cout << fmt::wrap( foo )可以找到的过载<<范围内fmt,如果没有找到调用<<上所包含的数据.

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