2

I'm trying to figure out how I can perform an operation at the time in which a function is called, for example:

ExampleClass eco;
eco.DoStuff(); 

At the point of eco.DoStuff(), I'd like to log to a file.

I'm trying to get something with overloaded operators but with no luck?

E.g.

void operator>>(ExampleClass eco, std::function<void(void)> DoStuff) 
{
 //Perform logging into a file
 DoStuff;
}

int main()
{
  ExampleClass eco;
  std::function<void(void)> func_pointer = std::bind(&ExampleClass::DoStuff, &eco, 2);
  eco >> func_pointer; 
}

This works, however I can't use a flexible parameter for DoStuff, as this has to be explicitly set in func_pointer.

Additionally, creating function pointers for every single method in my class isn't an option.

What's the best way of doing this?

Babra Cunningham
  • 2,949
  • 1
  • 23
  • 50

1 Answers1

2

What about using a templated definition for the output operator?

template<typename Function>
void operator>>(ExampleClass eco, Function DoStuff) 
{
 //Perform logging into a file
 DoStuff();
}

A possible variation on this method is to supply functors to the operator>> overload that take eco as an lvalue argument:

template <typename MemberCall>
ExampleClass& operator>>(ExampleClass& eco, MemberCall mem_call){
    eco.log();
    mem_call(eco);
    return eco; // returned lvalue eco allows chaining
}

Ease of use could be improved by creating a helper function to convert member function pointers and arguments to functors taking an ExampleClass lvalue argument:

template <typename MemberFunctionType, typename...Args>
auto member_call(MemberFunctionType mem_fn, Args&&...args){
    return [=](ExampleClass& object){
        return (object.*mem_fn)(args...);
    };
}

to be used like so:

eco
    >> member_call(&ExampleClass::DoStuff, 2)
    >> member_call(&ExampleClass::DoStuff, 4);

It should be noted that the errors should you supply an invalid argument to this construct may not be pretty, since member_call returns lambdas. If it becomes a problem, creating and returning a custom functor type will likely improve error message quality.

jaggedSpire
  • 4,423
  • 2
  • 26
  • 52
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • An added benefit of this method is that instead of using `std::bind`, you may simply do `eco >> [&](){eco.DoStuff(2);};` – jaggedSpire Jan 30 '17 at 19:02
  • Is there an approach that avoids having to make the `eco.DoStuff` explicitly in `int main`.. E.g. `eco >> DoStuff(22);` ? Isn't this solution also just using a template, where I still have to use a `std::bind`? – Babra Cunningham Jan 30 '17 at 19:05
  • Are you only going to be using member functions with the same number of arguments? – jaggedSpire Jan 30 '17 at 19:06
  • No, the class' member functions have a variety of arguments. – Babra Cunningham Jan 30 '17 at 19:07
  • You have to specify the arguments you're going to supply to the function somehow. There *are* ways to shorten it, though. – jaggedSpire Jan 30 '17 at 19:09
  • [Here's an example](http://coliru.stacked-crooked.com/a/6fe1b0e637e40a83). This is essentially the same idea as above, except it uses functors that take a single argument of type `ExampleClass`, and offers a helper function to generate those functors. (Not adding as different answer for that reason, actually) And it uses the operator chaining so happily (ab)used by iostreams. – jaggedSpire Jan 30 '17 at 19:24
  • @jaggedSpire Well, that might be a good extension to add up in my answer. I left binding to the `eco` parameter open. I'm going to mark that as community wiki answer now, feel free to improve it. – πάντα ῥεῖ Jan 30 '17 at 19:27
  • If you decide to use the linked method in any extensive way you'll probably want to make a custom functor class to try to improve the error messages you'll get--applying the wrong type to a functor returned by a templated function with an `auto` returned lambda is...unlikely to be pretty. – jaggedSpire Jan 30 '17 at 19:28
  • @jaggedSpire You may add a separate answer as well, giving you a chance to gain rep. – πάντα ῥεῖ Jan 30 '17 at 19:33
  • @πάνταῥεῖ edited. (Thanks, but I'm not too attached to gaining rep these days.) – jaggedSpire Jan 30 '17 at 19:41
  • @jaggedSpire You've got spine. I appreciate and respect this most in these days of darkness. – πάντα ῥεῖ Jan 30 '17 at 19:47
  • @πάνταῥεῖ Thank you. – jaggedSpire Jan 30 '17 at 19:59
  • I'll defer that bounty as soon it's possible. – πάντα ῥεῖ Jan 30 '17 at 20:00
  • I don't know what to say. Thank you, again. – jaggedSpire Jan 30 '17 at 20:08
  • @jaggedSpire I'm referring [to that one](http://stackoverflow.com/questions/37618213/when-is-a-private-constructor-not-a-private-constructor). That's meant as an incentive for you. – πάντα ῥεῖ Jan 30 '17 at 20:10