C++ 覆盖运算符<&书信电报;适用于所有类型

C++ 覆盖运算符<&书信电报;适用于所有类型,c++,c++11,operator-overloading,overloading,name-lookup,C++,C++11,Operator Overloading,Overloading,Name Lookup,当我试图编写std::cout时,会出现编译错误,这让我有点恼火。一般来说,你不能。但这是,所以你可以,如果你愿意成为邪恶的 namespace named_operator { template<class D>struct make_operator{constexpr make_operator(){}}; template<class T, char, class O> struct half_apply { T&& lhs; O con

当我试图编写
std::cout时,会出现编译错误,这让我有点恼火。一般来说,你不能。但这是,所以你可以,如果你愿意成为邪恶的

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;
  }
}
名为_运算符的命名空间{
templatestruct make_操作符{constexpr make_操作符(){};
模板结构half_apply{T&&lhs;O const&O;};
模板

half_apply operator一个答案可能是在管道操作中用薄薄的包装纸包裹ostream


这个薄包装可以有通用模板操作符@IgorTandetnik,但不完全是这样。对于barber来说,它看起来像是“今晚理发师会给所有还没有刮胡子的人刮胡子”。我想为其他地方的函数不接受的所有类型定义函数。我看不到任何悖论。这可能会很困难在格式良好的程序中使用这样的运算符是不可能的。如果您成功地实现了运算符,则运算符的定义将取决于在其实例化点处恰好可见哪些专门化。在不同的翻译单位中,甚至在单个翻译单位中,这些专门化可能会有所不同(per[temp.point]/8),这将违反ODR,导致程序格式不正确,无需诊断。@IgorTandetnik哦,好吧……谢谢你的链接,我将阅读标准,了解我问题的荒谬之处,或者改写它。这不是一个直接的答案,但涵盖了一些相同的问题。这是一个解决方法,你可以通过某种方式使你的
我刚才举了一个例子从你的简介中挖掘出这些命名操作符:)这是一个从C++的阴暗面来的非常好的东西。虽然它不能解决我的问题。事实上,这里有一个基本原理:我正在做有竞争力的编程,你花在找出代码为什么不编译的那些时间上是很珍贵的。所以我不需要一个生产质量。这是一个很好的解决方案,但它是一个特别的黑客程序,可以警告我关于cout ing std::vector的问题,并且不需要考虑ODR、多个翻译单元和类似的问题。您链接的问题可能会有所帮助,我现在正在研究它。@IvanSmirnov然后编写
print(ostream&,Args const&…)
而不是使用

template<typename T>
std::ostream& operator<<(std::ostream& out, const T&)
{
    return out << "my operator";
}
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;