c++ boost::any to define my own print ,

后端 未结 4 1020
野的像风
野的像风 2021-02-04 22:00

Am struggling a lot to find how to do to use boost::any to create a print function that can print any type using template first.

template 

        
4条回答
  •  谎友^
    谎友^ (楼主)
    2021-02-04 22:42

    Very nice answer by Pawel Zubrycki (mentioning Björn Karlsson's book).

    But the code has a few errors in the following lines:

    // ...
    o << *boost::any_cast(a);    // should be:   o << *boost::any_cast(&a);
    // ...
    a.streamer_->print(o, a);       // should be:   a.streamer_->print(o, a.o_);
    

    Here's a corrected version of Pawel Zubrycki's answer that works (partially...)

    #ifndef ANY_OUT_H
    #define ANY_OUT_H
    
    #include 
    #include 
    
    struct streamer {
      virtual void print(std::ostream &o, const boost::any &a) const =0;
      virtual streamer * clone() const = 0;
      virtual ~streamer() {}
    };
    
    template 
    struct streamer_impl: streamer{
      void print(std::ostream &o, const boost::any &a) const { o << *boost::any_cast(&a); }
      streamer *clone() const { return new streamer_impl(); }
    };
    
    class any_out {
      streamer *streamer_;
      boost::any o_;
      void swap(any_out & r){
        std::swap(streamer_, r.streamer_);
        std::swap(o_, r.o_);
      }
    public:
      any_out(): streamer_(0) {}
      template any_out(const T& value)
        : streamer_(new streamer_impl()), o_(value) {}
      any_out(const any_out& a)
        : streamer_(a.streamer_ ? a.streamer_->clone() : 0), o_(a.o_) {}
    
      template 
      any_out & operator=(const T& r) {
        any_out(r).swap(*this);
        return *this;
      }
      ~any_out() { delete streamer_; }
    
      friend std::ostream &operator<<(std::ostream& o, const any_out & a);
    };
    
    std::ostream &operator<<(std::ostream& o, const any_out & a) {
      if(a.streamer_)
        a.streamer_->print(o, a.o_);
      return o;
    }
    
    #endif
    

    This test-code works:

    {
       any_out a = 5;
       std::cout << a << std::endl;
    }
    

    However!!!!

    The following does not work:

    int main()
    {
      char str[] = "mystring";
      any_out a = str;
      std::cout << a << std::endl;
    
      a = "myconststring";
      std::cout << a << std::endl;
    }
    

    Here nothing gets printed.

    Why??

    Well the type is messed up, in the following constructor

    any_out(const T& value)
    

    if we then instantiate streamer as

    new streamer_impl()
    

    Removing the reference from the constructor, i.e.

      any_out(const T value)
    

    ... is one solution.

    Another solution is to leave the reference and tweak the template instantiation of streamer_impl. See below

    Which brings as to the following recommened solution is:

    #ifndef ANY_OUT_H
    #define ANY_OUT_H
    
    #include 
    #include 
    
    struct streamer {
      virtual void print(std::ostream &o, const boost::any &a) const =0;
      virtual streamer * clone() const = 0;
      virtual ~streamer() {}
    };
    
    template 
    struct streamer_impl: streamer{
      void print(std::ostream &o, const boost::any &a) const { o << boost::any_cast(a); }
      streamer *clone() const { return new streamer_impl(); }
    };
    
    class any_out {
      boost::any o_;
      streamer *streamer_;
      void swap(any_out & r){
        std::swap(streamer_, r.streamer_);
        std::swap(o_, r.o_);
      }
    public:
      any_out(): streamer_(0) {}
    
      template any_out(const T& value)
        : o_(value),
    #if 1
          streamer_(new streamer_impl::type>)
    #else
          streamer_((o_.type() == typeid(const char *))
                    ? static_cast(new streamer_impl)
                    : static_cast(new streamer_impl))
    #endif
      {
      }
    
      // template any_out(const T value)
      //   : o_(value),
      //     streamer_(new streamer_impl)
      // {
      // }
    
      any_out(const any_out& a)
        : o_(a.o_), streamer_(a.streamer_ ? a.streamer_->clone() : 0) {}
    
      template 
      any_out & operator=(const T& r) {
        any_out(r).swap(*this);
        return *this;
      }
      ~any_out() { delete streamer_; }
    
      friend std::ostream &operator<<(std::ostream& o, const any_out & a);
    };
    
    std::ostream &operator<<(std::ostream& o, const any_out & a) {
      if(a.streamer_)
        a.streamer_->print(o, a.o_);
      return o;
    }
    
    #endif
    

    The test-code that gave some trouble above, now works nicely (with the "recommeded solution"):

    int main()
    {
      char str[] = "mystring";
      any_out a = str;
      std::cout << a << std::endl;
    
      a = "myconststring";
      std::cout << a << std::endl;
    }
    

提交回复
热议问题