簡體   English   中英

std::pair 的重載運算符&gt;&gt;<int, int>

[英]Overload operator>> for std::pair<int, int>

我正在嘗試在std::pair<int, int>上使用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.txt 必須與 my_pair 位於相同的命名空間中。

這樣做會導致未定義的行為,因為我會將函數添加到命名空間 std。

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

這個問題的解決方案是什么?

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

您可以在流上重載(以某種方式標記它),而不是 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;
    }
}

See it Live On Coliru ,打印:

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

這樣做會導致未定義的行為,因為我會將函數添加到命名空間 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;
}

事實上,你可能應該這樣做,因為 std::pair 更像是一個構建塊,而不是應該用來表示語義信息的東西(而不是應該直接打印到流的東西)。

我知道你說過你不想要這個,但我肯定使用繼承:

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

現場演示

你的my::my_pair字面意思my::my_pair std::pair<int, int> 你只需要它在你自己的命名空間中是一個不同的類型。 這就是繼承的用途。

我只是把這個留在這里是為了展示它是多么容易做,並解釋為什么我認為你應該這樣做。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM