views:

110

answers:

5

I would like to overload << operator for chaining like below

function1(param1, param2)<< obj2 << obj3 << string4

function1 would return an object.

What I want to do is after string4, I need to call a function using param1, param2.

My questions will be

  1. How do I know string4 is the last parameters in the expression and hence I need to call another function2 using param1 and param2 or it isn't possible to do so?

  2. How do I pass param1 and param2 to the function to be called? I could not store the param1 and param2 in the object as it is a multithreaded.

Thanks.

A: 

How do I know string4 is the last parameters in the expression and hence I need to call the function using param1 and param2 or it isn't possible to do so?

function1(param1, param2)<< obj2 << obj3 << string4

doesn't do what you think it does. Here function1 is evaluated first, the resulting object is used to call operator<< with obj2 as an argument and so on...

If you want to call function1 at the end, it should occur after you have called operator<< with string4 as an argument.

How do I pass param1 and param2 to the function to be called? I could not store the param1 and param2 in the object as it is a multithreaded.

Your op<< should return an object of type T which has op() defined so that you can all it with param1 and param2 at the very end.

dirkgently
Sorry for the confusion caused, the function I need to call is another function, function2..
Steveng
A: 

If function1 is returning something (say an int), you should be able to delay al computations until it's value is used. . You should return an object that can be converted to an int (by implementing int operator int() as a member function).

In function1's implementation you construct it. The object will also implement <<. In that member function that does the conversion, you use all the values you collected as parameters and passed in with the << operator.

jdv
I do wonder wy you need this behavior. It is somewhat counterintuitive if you're familiar to read C++.
jdv
I want to create an expression that could print string from different objects and write to the file only once... Hence function2 is the call to write to the file. Param1 and param2 is the file path info...
Steveng
+1  A: 

You can return a helper object from function1 by value which calls function2 in it's destructor.

Consider this example:

#include <iostream>

using namespace std;

void function2( int i, int j ) {
    cout << "function2 called with " << i << " and " << j << endl;
}

struct Function2Caller {
  Function2Caller( int param1, int param2 ) : m_param1( param1 ), m_param2( param2 ) {}
  ~Function2Caller() { function2( m_param1, m_param2 ); }

  int m_param1, m_param2;
};

Function2Caller &operator<<( Function2Caller &obj, int x ) {
    cout << "Streaming " << x << endl;
    return obj;
}

Function2Caller function1( int i, int j ) {
    cout << "function1 called with " << i << " and " << j << endl;
    return Function2Caller( i, j );
}

int main() {
    function1( 2, 3 ) << 4 << 6;
}

This program prints

function1 called with 2 and 3
Streaming 4
Streaming 6
function2 called with 2 and 3

The idea is that at the end of your line, the Function2Caller object goes out of scope and the destructor then does its work.

Please note that when implementing this you should probably forbid copying of Function2Caller objects and make function1 the only one who can call the Function2Caller constructor.

Frerich Raabe
Thanks for the reply. For the temporary object generated, when exactly in the expression is it being destructed?
Steveng
Steveng
@Steveng: The temporary object is destroyed at the end of the statement. In `function1(1, 3) << x << y;` that would be right at the `;`. Also, yes, you can implement `operator<<` on that object. The operator<< can be a member function (as in my example) or a free function. I updated my answer with working example code.
Frerich Raabe
+1  A: 

As Frerich Raabe noted, one possible solution is to use the destructor of a temporary object. It does impose, however, that you will somehow NEED to call all the arguments inline, thus prohibiting the following syntax:

auto stream = function1(param1, param2) << param3;
stream << param4;
stream << stringG; // call here

The IO Stream library in the Standard Library circumvents the issue by using a global object as a "marker": std::endl. This could be another option.

Note that if you go the marker way, you can lift the requirement of no copying.

In the end, it's more a matter of design that a matter of implementation, so it's your call.

class Stream
{
public:
  struct Marker {};
  static Marker End;

  Stream(type1, type2);

  void operator<<(Marker) const { function2(m1,m2); }
  Stream& operator<<(...);

private:
  type1 m1;
  type2 m2;
};

Have fun :)

Matthieu M.
A: 

You pass a functor at the end its easier this way

 class myfun {
 public:
         void operator()(const string& param1, const string& param2, const string& values) const {
                 std::cout << "param1: " << param1 << "param2: " << param2 << " value: " << values << std::endl;
         }
 };

 class A {
         string m_param1, m_param2;
         string values;
 public:
         A(string param1, string param2):m_param1(param1), m_param2(param2) { }

         A& operator << (const string& str) {
                 values += str;
                 return *this;
         }

         A& operator << (const myfun& myfun) {
                 myfun(m_param1, m_param2, values);
                 return *this;
         }
         };

 A fun(string param1, string param2) {
       return A(param1, param2);
 };

 int main() {
         fun("a", "b") << "xyz" << myfun();
         return 0;
 }
aeh