重载运算符>> for std :: pair <int,int>

the*_*meg 9 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;
}
Run Code Online (Sandbox Code Playgroud)

如果我理解正确,为了使ADL工作,operator >>必须与my_pair在同一个命名空间中,所以std.

这样做会导致未定义的行为,因为我将向命名空间std添加函数.

我想避免继承,就像在struct my_pair : std::pair<int, int>.

什么可以解决这个问题?

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

seh*_*ehe 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";
}
Run Code Online (Sandbox Code Playgroud)

这样,您可以在您控制的命名空间上进行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;
    }
}
Run Code Online (Sandbox Code Playgroud)

看到Live On Coliru,它打印:

std::pair{42, I'm gonna try}
std::pair{1729, science}
Run Code Online (Sandbox Code Playgroud)


utn*_*tim 2

这样做会导致未定义的行为,因为我将向命名空间 std 添加函数。

我想避免继承,如 struct my_pair : std::pair 中所示。

我想说“继承”,但你驳回了......

您可以使用封装,只需添加另一个强类型std::pair<int,int>(但在这种微不足道的情况下,您可能最好使用自定义结构 - 您的注释代码):

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;
}
Run Code Online (Sandbox Code Playgroud)

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