我在
https://stackoverflow.com/a/51951315/1908650中询问了以下内容:
I want to overload
template<class T> ostream& operator<<(ostream& os,const optional<unique_ptr<T>>&
).
在评论中,@ Yakk – Adam Nevraumont指出:
The answer to that question is “you cannot”. There is no good legal way to do that for a generic type T; I could explain why,but it would take a new question/answer to do so
我正在创造一个新的Q.以接受这种报价……
解决方法
在与类型关联的命名空间中重载运算符的适当位置.
对于std :: optional< std :: unique_ptr< T>>有一个关联的命名空间std始终存在(来自ostream和optional和unique_ptr),以及与T关联的任何命名空间.如果要为所有类型重载,与T关联的命名空间对您没用.
在std中引入新函数或重载是不合法的;在某些有限的情况下,您可以引入专业化,但这些都不适用于此.添加<<的新重载到std会使您的程序生成错误,无需诊断. 您可以(A)使用自己命名空间中的装饰unique_ptr或选项,或者(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)}; } }
然后std :: cout<< fmt :: wrap(foo)可以找到<<的重载在fmt内,如果没有找到,则调用<<关于所包含的数据. 这也支持fmt :: wrap(std :: cout)而不是包装参数.可能有错别字.