Prasad
Prasad

Reputation: 67

C++: Overloading << operator with function pointers

I have a class "stampstream" that is essentially intended to work like 'cout'. The two functions that follow are outside the class. This is the part that works.

class stampstream: public std::ostream
{
    //code
    stampstream& operator<<(stampstream& (*x)(void))
    {
        //code
    }
    //code
};

stampstream& endr()
{
    //nocode
}

stampstream& (*endrow)(void)=endr;

In main:

stampstream s;
s << "teststring1" << endrow;

Note that "endrow" is essentially 'endl'. This part works perfectly fine, compiles and executes with the right output. Now, I'm trying to overload << with another possible row(int) function. This is the part that doesn't work. Again, it's part of the same class as above and the following 2 functions are outside the class.

class stampstream: public std::ostream
{
    //code
    stampstream& operator<<(stampstream& (*r)(int y))
    {
        //code
    }
    //code
};

stampstream& ro(int y)
{
    //nocode
}

stampstream& (*row)(int)=ro;

In main:

s << "teststring2" << row(5);

This is the error I get:

error: invalid user-defined conversion from ‘stampstream’ to ‘stampstream& (*)(int)’ [-fpermissive]

What am I doing wrong with row ?

Upvotes: 1

Views: 600

Answers (2)

David G
David G

Reputation: 96810

Since Chris has already answered your question, I wanted to advise you of alternatives to your current method:

  1. Your stampstream class should use a specialized std::streambuf that writes out the stamp inside overflow(). There's no need to extend an std::ostream and reimplement the input operators. For an example of how to do this, see this thread.

  2. You seem to be using endrow and row like manipulators. Operator overloads already exist for manipulators that do not take arguments at the call site. You can have endrow take and return an object of type std::ostream&. For row you can have it return a class that overloads the inserter to allow the syntax you want:

    struct row_impl
    {
        row_impl(int row) : row(row) { }
        // Write out the row and return the stream
        friend std::ostream& operator<<(std::ostream& os, row_impl const& rimpl);
    private:
        int row;
    };
    
    std::ostream& operator<<(std::ostream& os, row_impl const& rimpl)
    {
        // This is where the code for your original row() function goes
    }
    
    // write out to and return the stampstream instance
    std::ostream& endrow(std::ostream& os);
    
    row_impl row(int row)
    {
        return row_impl(row);
    }
    

    Now s << endrow and s << row(5) will work without having to add anything to your stampstream class.

Upvotes: 2

Chris Dodd
Chris Dodd

Reputation: 126203

The problem is that in

s << "teststring2" << row(5);

function call has higher precedence than <<, so this calls the function row points at and then tries to pass its return value (a stampstream &) to operator<<.

What you want is

s << "teststring2" << row;

This doesn't call the function and instead passes the pointer to operator<<. Inside that function, when you want to call x, you'll need to provide the argument.

It sounds like what you are trying to do is to have a function row that creates a functor object that you can then pass to operator<<. You can do that in C++11 with a lambda:

class stampstream: public std::ostream
{
    //code
    stampstream& operator<<(std::function<stampstream&(void)> r)
    {
        //code
    }
    //code
};

std::function<stampstream&(void)> row(int x)
{
    return [x]()->stampstream & {
        //code
    }
}

Which you can call as:

s << "teststring2" << row(5);

The call to row happens first, which constructs a lambda and returns it (but doesn't yet run the code in it). The functor is passed to operator<< and when that function calls r, it will call the code in the lambda (which can refer to the x param, which was bound by value, so copied into the lambda.)

Upvotes: 3

Related Questions