Enabling Classes for Use with boost::lexical_cast

2019-04-26 20:23发布

问题:

Code snippet from lexical_cast:

class lexical_castable {
public:
  lexical_castable() {};
  lexical_castable(const std::string s) : s_(s) {};

  friend std::ostream operator<<
    (std::ostream& o, const lexical_castable& le);
  friend std::istream operator>>
    (std::istream& i, lexical_castable& le);

private:
  virtual void print_(std::ostream& o) const {
    o << s_ <<"\n";
  }

  virtual void read_(std::istream& i) const {
    i >> s_;
  }

  std::string s_;
};

std::ostream operator<<(std::ostream& o,
  const lexical_castable& le) {
  le.print_(o);
  return o;
}

std::istream operator>>(std::istream& i, lexical_castable& le) {
  le.read_(i);
  return i;
}

Based on document,

template<typename Target, typename Source>
  Target lexical_cast(const Source& arg);

1> Returns the result of streaming arg into a standard library string-based stream and then out as a Target object.

2> Source is OutputStreamable

3> Target is InputStreamable

Question1> For User Defined Type (UDT), should the OutputStreamable or InputStreamable always have to deal with std::string? For example, given a class containing a simple integer as member variable, when we define the operator<< and operator>>, what is the implementation code looks like? Do I have to convert the integer as a string? Based on my understanding, it seems that UDT always has to deal with std::string in order to work with boost::lexical_cast and boost::lexcial_cast needs the intermediate std::string to do the real conversion jobs.

Question2> Why the return value of operator<< or operator>> in above code is not reference to std::ostream& or std::istream& respectively?

回答1:

To make your class usable with lexical_cast, just define the "stream" operators for it. From Boost.LexicalCast Synopsis:

  • Source is OutputStreamable, meaning that an operator<< is defined that takes a std::ostream or std::wostream object on the left hand side and an instance of the argument type on the right.
  • Target is InputStreamable, meaning that an operator>> is defined that takes a std::istream or std::wistream object on the left hand side and an instance of the result type on the right.
  • Target is CopyConstructible [20.1.3].
  • Target is DefaultConstructible, meaning that it is possible to default-initialize an object of that type [8.5, 20.1.4].

:

// either inline friend, out-of-class friend, or just normal free function
// depending on whether it needs to access internel members
// or can cope with the public interface
// (use only one version)
class MyClass{
  int _i;
public:
  // inline version
  friend std::ostream& operator<<(std::ostream& os, MyClass const& ms){
    return os << ms._i;
  }

  // or out-of-class friend (friend declaration inside class only)
  friend std::ostream& operator<<(std::ostream& os, MyClass const& ms);

  // for the free function version
  int get_i() const{ return _i; }
};

// out-of-class continued
std::ostream& operator<<(std::ostream& os, MyClass const& ms){
  return os << ms._i;
}

// free function, non-friend
std::ostream& operator<<(std::ostream& os, MyClass const& ms){
  return os << ms.get_i();
}

The same of course for operator>>.