Domanda

I'm debugging a program and I would like to make printing from that pattern:

 std::cout << firstVar << ", " << secondVar << ", " << thirdVar << endl ;

shorter, i.e, the same thing should happen if we will write the code:

shortPrint(std::cout) << firstVar << secondVar << thirdVar;

note: there is no limit for the variables quantity, it can be 1 and it can be 20, so that should also work:

shortPrint(std::cout) << firstVar << secondVar << thirdVar << anotherVar << oneMoreVar;

Someone told me that the easiest wat to do that is to create class that is called "shortPrint".

Can anyone help me figuring this out?

For start, I would say that I only need to implement a constructor and operator << overloading, but I'm not sure how to do that exactly in that case.

È stato utile?

Soluzione

Yes create a shortPrint class with an appropriate overloaded operator. Something like this :

class shortPrint {
  ostream &o;
public:
  shortPrint(ostream &o) : o(o) {}
  template <typename T> shortPrint &operator<<(const T &t) {
    o << t << ',';
    return *this;
  }
  // support for endl, which is not a value but a function (stream->stream)
  shortPrint &operator<<(ostream& (*pf)(std::ostream&)) {
    o << pf;
    return *this;
 }
};

That should work (basically).

To eliminate the problem of extra commas use this :

class shortPrint {
  class shortPrint2{
    shortPrint &s;
  public:
    shortPrint2(shortPrint &s) : s(s) {}
    template <typename T> shortPrint2 &operator<<(const T &t) {
      s.o << ',' << t ;
      return *this;
    }
    shortPrint &operator<<(ostream& (*pf)(std::ostream&)) {
      s.o << pf;
      return s;
    }
  };
  ostream &o;
  shortPrint2 s2;
public:
  shortPrint(ostream &o) : o(o), s2(*this) {}
  template <typename T> shortPrint2 &operator<<(const T &t) {
    o << t;
    return s2;
  }
  shortPrint &operator<<(ostream& (*pf)(std::ostream&)) {
    o << pf;
    return *this;
  }
};

Altri suggerimenti

You can do something like the following:

class _ostream_wrap
{
public:
    template <class T>
    _ostream_wrap& operator << (const T & v)
    {
        m_ost << "[ " << v << " ]";
        return (*this);
    }
    explicit _ostream_wrap(std::ostream & ost)
        :m_ost(ost)
    {}
private:
    std::ostream&   m_ost;
};

template <class OSTREAM>
_ostream_wrap shortPrint(OSTREAM & o)
{
    return _ostream_wrap(o);
}

//...
shortPrint(std::cout) << 1 << 2;

however this implementation will not work on rvalues:

//you can't do something like the following:
shortPrint(MyOstream(some_args)) << 1;

This is because the class _ostream_wrap keeps a reference to the stream and for rvalues case it needs to make a copy. To make a copy you need to have two implementations (this would be the final version):

template <class OSTREAM>
class _ostream_wrap
{
public:
    template <class T>
    _ostream_wrap<OSTREAM>& operator << (const T & v)
    {
        m_ost << "[ " << v << " ]";
        return (*this);
    }


public:
    //the constructor is harder to write so i decided 
    //that for this i will keep the member public
    OSTREAM     m_ost;
};

template <class OSTREAM>
_ostream_wrap<OSTREAM&> shortPrint(OSTREAM & o)
{
    _ostream_wrap<OSTREAM&> rvalue;
    rvalue.m_ost = o;
    return rvalue;
}
template <class OSTREAM>
_ostream_wrap<OSTREAM> shortPrint(const OSTREAM & o)
{
    _ostream_wrap<OSTREAM> rvalue;
    rvalue.m_ost = o;
    return rvalue;
}

Here's something with very basic functionality:

#include <iostream>

struct shortPrint {
    explicit shortPrint(std::ostream& os)
        : strm(&os), first(true) {}

    template<typename T>
    shortPrint& operator<<(T&& t)
    {
        if (first) {
            first = false;
        } else {
            *strm << ", ";
        }
        *strm << std::forward<T>(t);
        return *this;
    }

    shortPrint& operator<<( std::ostream& (*func)(std::ostream&) )
    {
        *strm << func;
        return *this;
    }

private:

    std::ostream* strm;
    bool first;
};

int main()
{
    int i = 3;
    shortPrint(std::cout) << "1" << 2 << i << std::endl;
    shortPrint(std::cout) << 4;
}

The tricky part is getting the commas to be printed correctly. I chose to print them before every streamed object, except before the very first one. As you can see, there's one general operator<< template that simply prints the comma and forwards the argument. The next problem are stream manipulators, because we don't want to print commas before them. The other operator<< overload takes care of that. If you want to be more generic, there's two more you need to take care of (see no. 9 here ).

Hope that helps.

Return the ostream from the function. Something like:

std::ostream &shortPrint(std::ostream &out) {
    //whatever you need here
    return out;
}

Edit: you the kind of formatting you need, you need to make a class with overloaded stream operator that returns the class. But you need to keep the reference to the needed stream in the class.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top