覆盖运算符<<适用于所有类型
Overriding operator<< for all types
我对尝试编写std::cout << x
时出现的编译错误有点恼火,并且左移运算符未为x
定义。无法将 x 转换为这个,无法将 x 转换为那个...几个无用的错误消息屏幕。
我想专门针对尚未定义此类运算符的所有类型进行operator<<(std::ostream&, const T&)
。在里面,我可以放一个静态断言,并使编译错误消息比现在更清晰。
我的第一次尝试如下。
template<typename T, typename = void>
struct Has : public std::false_type {};
template<typename T>
struct Has<T, decltype(void(
std::declval<std::ostream&>() << std::declval<T>()
))> : public std::true_type {};
template<typename T>
auto operator<<(std::ostream& out, const T&)
-> typename std::enable_if<
!Has<T>::value,
std::ostream&>::type
{
return out << "my operator";
}
它无法编译,因为超出了最大模板深度。事实上,我的operator<<
呼吁Has
专业化,以便要求operator<<
,再次检查我的超负荷,等等,等等。
最简单的版本也不起作用:std::ostream& << const char*
的模棱两可的重载。嗯,意料之中。
template<typename T>
std::ostream& operator<<(std::ostream& out, const T&)
{
return out << "my operator";
}
如何完成任务?或者,一般来说,我如何为所有参数类型定义函数,但为那些已经可以传递给函数的参数类型定义函数?
一般来说你不能
。 但这是 c++,所以如果你愿意作恶,你可以。
namespace named_operator {
template<class D>struct make_operator{constexpr make_operator(){}};
template<class T, char, class O> struct half_apply { T&& lhs; O const& o; };
template<class Lhs, class Op>
half_apply<Lhs, '<', Op> operator<( Lhs&& lhs, make_operator<Op>const & o ) {
return {std::forward<Lhs>(lhs), o};
}
template<class Lhs, class Op, class Rhs>
auto operator<( half_apply<Lhs, '<', Op>&& lhs, Rhs&& rhs )
-> decltype( named_invoke( std::forward<Lhs>(lhs.lhs), lhs.o, std::forward<Rhs>(rhs) ) )
{
return named_invoke( std::forward<Lhs>(lhs.lhs), lhs.o, std::forward<Rhs>(rhs) );
}
}
namespace utility {
namespace details {
template<class...>struct voider{using type=void;};
}
template<class...Ts>using void_t=typename details::voider<Ts...>::type;
namespace details {
template<template<class...>class, class, class...>
struct can_apply:std::false_type{};
template<template<class...>class Z, class...Ts>
struct can_apply<Z, void_t<Z<Ts...>>, Ts...>:std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z,void,Ts...>;
}
namespace streaming {
namespace details {
template<class T>
using ostream_r = decltype( std::cout << std::declval<T&&>() );
}
template<class T>
using can_ostream = utility::can_apply<details::ostream_r, T>;
struct out_tag: named_operator::make_operator<out_tag> {};
static const out_tag out;
template<class T>
std::ostream& named_invoke( std::ostream& os, out_tag, T const& t ) {
static_assert( can_ostream<T const&>{}, "This type cannot be streamed" );
return os<<t;
}
template<class T,
std::enable_if_t< can_ostream<T const&>{}, int> =0 // breaks MSVC
>
std::ostream& named_invoke( std::ostream& os, out_tag, T const& t ) {
return os<<t;
}
}
如果我写对了,
struct no_worky {};
no_worky bob;
using streaming::out;
std::cout <out< bob;
编译失败并生成友好消息,同时
std::cout <out< 7;
呼叫std::cout << 7
。
我认为这不值得。
一个答案可能是将 ostream 包裹在薄包装器中以进行管道操作?
此瘦包装器可以具有通用模板运算符<<成员,这反过来又检查包装的 std::ostream 上的真实运算符。但是,您可能会发现收到更不愉快的错误消息!
请注意,您还需要为 std::endl 及其亲属添加一个特定的处理程序,因为他们希望专门研究流宽度,您已经混淆了。
相关文章:
- ArduinoJson 6.15.2:JsonObject没有命名类型
- 防止主数据类型C++的隐式转换
- 大量序列中核苷酸类型的快速计数
- 如何从C++中的依赖类型中获得它所依赖的类型
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 是否可以初始化不可复制类型的成员变量(或基类)
- 如何获取std::result_of函数的返回类型
- 从父命名空间重载类型
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- Openssl 1.1.1d无效使用不完整的类型"struct dsa_st"
- 访问者访问变体并返回不同类型时出错
- 在VS2010-VS2015下编译时,如何使用decltype作为较大类型表达式的LHS
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- C++ 雷神库 - 使用资源加载器类时出现问题(不命名类型)
- 模板元程序查找相似的连续类型名称
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- 是否可以从int转换为enum类类型
- eigen :: llt&lt;eigen :: matrixxd&gt;具有不完整的类型
- std::pair的默认构造函数<>将基本类型(int等)设置为零