【问题标题】:Overload operator>> for std::pair<int, int>std::pair<int, int> 的重载运算符>>
【发布时间】:2015-08-18 23:08:06
【问题描述】:

我正在尝试在 std::pair&lt;int, int&gt; 上使用 boost::lexical_cast

#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 工作,运算符>> 必须与 my_pair 在同一个命名空间中,所以 std。

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

我想避免继承,如struct my_pair : std::pair&lt;int, int&gt;

有什么办法可以解决这个问题?

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

【问题讨论】:

  • @KirilKirov “我想避免继承”。别名不是类型。这是一个别名
  • @sehe - o,我没有注意到它是using,而不是真正的类型。我真的错过了一些东西:)

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


【解决方案1】:

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

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

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

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

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;
}

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

【讨论】:

  • 我认为没有理由不避免继承。 my_pair is-a std::pair&lt;int,int&gt; 这正是继承的用途。
  • @LightnessRacesinOrbit,我能看到继承的唯一原因是 OP 的问题:“我想避免继承,就像 struct my_pair : std::pair 一样。”。
  • 幸运的是,我没有受到愚蠢和无法解释的约束:这解决这个问题的最佳方法。 :)
【解决方案2】:

您可以在流上重载(以某种方式标记它),而不是 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}

【讨论】:

    【解决方案3】:

    我知道你说过你不想要这个,但我肯定使用继承:

    #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字面意思是一个std::pair&lt;int, int&gt;;您只需要它是您自己的命名空间中的不同类型。这就是继承的用途。

    我只是把它留在这里,以展示它是多么容易,并解释为什么我认为你应该这样做。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-10-29
      • 1970-01-01
      • 1970-01-01
      • 2020-10-22
      • 1970-01-01
      • 2014-03-03
      相关资源
      最近更新 更多