重载运算符&gt;&gt;对于std :: pair <int,int =“”>

时间:2015-06-04 11:02:06

标签: c++ boost std argument-dependent-lookup

我正在boost::lexical_cast上使用std::pair<int, int>

#include <iostream>
#include <utility>
#include <boost/lexical_cast.hpp>

namespace my
{
  // When my_pair is a user defined type, this program compiles
  // and runs without any problems.
  // When declaring my_pair as an alias of std::pair<int, int>,
  // it fails to compile

  /*
  struct my_pair
  {
      int first;
      int second;
  };
  */

  using my_pair = std::pair<int, int>;

  std::istream& operator>>(std::istream& stream, my_pair& pair)
  {
    stream >> pair.first;
    stream >> std::skipws;
    stream >> pair.second;
    return stream;
  }
}

int main()
{
  my::my_pair p = boost::lexical_cast<my::my_pair>("10 10");
  std::cout << p.first << " " << p.second << std::endl;
  return 0;
}

如果我理解正确,为了使ADL工作,运营商&gt;&gt;必须与my_pair位于同一名称空间中,所以std。

这样做会导致未定义的行为,因为我会在命名空间std。

中添加函数

我想避免继承,例如struct my_pair : std::pair<int, int>

这个问题的解决方案是什么?

我在OS X上使用clang ++ - 3.6。

3 个答案:

答案 0 :(得分:7)

您可以在流上重载(以某种方式对其进行标记),而不是对要传输的值进行ADL挂钩:

int main() {
    std::map<int, std::string> standback { { 42, "I'm gonna try" }, { 1729, "science" } };

    streaming::tag_ostream out = std::cout;

    for (auto& entry : standback)
        out << entry << "\n";
}

这样,您可以在您控制的命名空间上进行ADL挂钩。您可以使标记更通用(想想auto out = streaming::tag(std::cout))。

现在,一个简单的实现可能看起来像

namespace streaming {

    template <typename T>
    struct tag : std::reference_wrapper<T> {
        using std::reference_wrapper<T>::reference_wrapper;
    };

    using tag_ostream = tag<std::ostream>;

    template <typename T1, typename T2>
    static inline tag_ostream operator<<(tag_ostream os, std::pair<T1, T2> const& p) {
        os.get() << "std::pair{" << p.first << ", " << p.second  << "}";
        return os;
    }

    template <typename Other>
    static inline tag_ostream operator<<(tag_ostream os, Other const& o) {
        os.get() << o;
        return os;
    }
}

查看 Live On Coliru ,其中会打印:

std::pair{42, I'm gonna try}
std::pair{1729, science}

答案 1 :(得分:2)

  

这样做会导致未定义的行为,因为我会在命名空间std。

中添加函数      

我想避免继承,例如struct my_pair:std :: pair。

我想说“继承”,但你不予理会......

您可以使用封装,只需在struct my_pair { std::pair<int,int> value; // TODO: add any access interface here }; std::istream& operator>>(std::istream& stream, my_pair& pair) { stream >> pair.value.first; stream >> std::skipws; stream >> pair.value.second; return stream; } 上添加另一种强类型(但在这种简单的情况下,您可能最好使用自定义结构 - 您的注释代码):

Public Class Form2

Private WithEvents pd As New Printing.PrintDocument
Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
    Using bmp As New Bitmap(Form1.pb1.Width, Form1.pb1.Height)
        Form1.panel1.DrawToBitmap(bmp, New Rectangle(0, 0, Form1.pb1.Width, Form1.pb1.Height))
        e.Graphics.DrawImage(bmp, e.MarginBounds)
    End Using
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    PrintDocument1.Print()
End Sub 
End Class

事实上,你可能应该这样做,因为std :: pair更像是一个构建块,而不是用来表示语义信息的东西(而不是那些应该直接打印到的东西)一条小溪)。

答案 2 :(得分:2)

我知道你说你不想要这个,但我绝对使用继承:

#include <iostream>
#include <utility>
#include <boost/lexical_cast.hpp>

namespace my
{
   struct my_pair : std::pair<int, int> {};

   std::istream& operator>>(std::istream& stream, my_pair& pair)
   {
      stream >> pair.first;
      stream >> std::skipws;
      stream >> pair.second;
      return stream;
   }
}

int main()
{
    my::my_pair p = boost::lexical_cast<my::my_pair>("10 10");
    std::cout << p.first << " " << p.second << std::endl;
}

live demo

您的my::my_pair字面上是-a std::pair<int, int>;你只需要它在你自己的命名空间中成为一个独特的类型。这就是继承的目的。

我刚刚离开这里,以表明这是多么容易,并解释为什么我认为你应该这样做。