c++ - 为什么不能为涉及第三方代码的模板类覆盖 operator<<?
问题描述
我在https://stackoverflow.com/a/51951315/1908650中询问了以下内容 :
我想超载
template<class T> ostream& operator<<(ostream& os, const optional<unique_ptr<T>>&
)。
在评论中,@Yakk - Adam Nevraumont 指出:
这个问题的答案是“你不能”。对于泛型类型 T,没有好的合法方法可以做到这一点;我可以解释原因,但这样做需要一个新的问题/答案
我正在创建一个新的 Q. 来接受好心的提议...
解决方案
在与类型关联的命名空间中重载运算符的适当位置。
因为std::optional<std::unique_ptr<T>>
有一个std
始终存在的关联命名空间(来自ostream
andoptional
和unique_ptr
),再加上与 . 关联的任何命名空间T
。由于您想为所有类型重载,因此关联的命名空间T
对您没有用处。
在 ;中引入新函数或重载是不合法的std
。在某些有限的情况下,您可以引入专业化,但它们都不适用于这里。添加新的重载<<
tostd
会使您的程序格式错误,无需诊断。
您可以 (A) 使用您自己的命名空间中的 decorated unique_ptr
or optional
s,或者 (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)
而不是包装参数。可能有错别字。