Join the Stack Overflow Community
Stack Overflow is a community of 6.7 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

I have :

class Foo {

public:

void log(){

}

void a(){
    log();
}

void b(){
   log();
}

};

Is there a way that I can have each method of Foo, call log(), but without me having to explicitly type log() as the first line of each function ? I want to do this, so that I can add behaviour to each function without having to go through each function and make sure the call is made, and also so that when I add new functions, the code is automatically added...

Is this even possible ? I can't imagine how to do this with macro's, so not sure where to begin... The only way I have thought of so far, is to add a "pre-build step", so that before compiling I scan the file and edit the source code, but that doesn't seem very intelligent....

EDIT: Just to clarify - I don't want log() to call itself obviously. It doesn't need to be part of the class.

EDIT: I would prefer using methods that would work cross platform, and using only the stl.

share|improve this question
    
It could be done with macros, but it's not really anything I recommend (and therefore won't show). The best way IMO is to be explicit about it, and just call the function first thing you do. That will make it easy for future readers (including you) to understand what's going on. – Some programmer dude 3 hours ago
    
@Someprogrammerdude well thats exactly what I'm trying to avoid - as in, I do not want to explicitly have to add it to each method, as then anytime a new method is added, someone will have to "know" to add a call to log() – John 3 hours ago
1  
google C++ aspect programming. I have not used, this is not recommendation, only point worth reading – Jacek Cz 3 hours ago
    
Adding the explicit call will be easier than suddenly wondering why log is called when the code doesn't seem to actually call it. Hiding such details will make your code very hard to maintain a couple of years down the line, even if it is yourself that comes back to it. – Some programmer dude 3 hours ago
2  
You can create function logAndCallFunc() with one parameter - pointer to function you want to call after log(). – Yuriy Ivaskevych 3 hours ago
up vote 12 down vote accepted

Thanks to the unusual properties of operator ->, we can inject code before any member access, at the expense of a slightly bent syntax:

// Nothing special in Foo
struct Foo {
    void a() { }
    void b() { }
    void c() { }
};

struct LoggingFoo : private Foo {
    void log() const { }

    // Here comes the trick
    Foo const *operator -> () const { log(); return this; }
    Foo       *operator -> ()       { log(); return this; }
};

Usage looks as follows:

LoggingFoo f;
f->a();

See it live on Coliru

share|improve this answer
    
Can you explain a bit please ? This seems to work! That's incredible.. I had no idea you could do that. What are the risks of doing something like this ? – John 3 hours ago
1  
@Quentin: this makes the assumption that log() is a nullary function, which seems unrealistic to me. I would expect a() to log something different than b(). – Vittorio Romeo 3 hours ago
1  
@VittorioRomeo it does -- depends on OP's actual need, but the question is specified like that :) / Off-topic: I loved your black-magic autothreading ECS framework, and the presentation you gave of it :D – Quentin 2 hours ago
1  
@Quentin: fair enough. Glad you liked my work! :) – Vittorio Romeo 2 hours ago
1  
@xDaizu aaah, the ancestral clan wars between JS and C++, each finding the other one's syntax terrifying :) – Quentin 42 mins ago

This a minimal (but pretty general) solution to the wrapper problem:

#include <iostream>
#include <memory>

template<typename T, typename C>
class CallProxy {
    T* p;
    C c{};
public:
    CallProxy(T* p) : p{p} {}
    T* operator->() { return p; } 
};

template<typename T, typename C>
class Wrapper {
    std::unique_ptr<T> p;
public:
    template<typename... Args>
    Wrapper(Args&&... args) : p{std::make_unique<T>(std::forward<Args>(args)...)} {}
    CallProxy<T, C> operator->() { return CallProxy<T, C>{p.get()}; } 
};

struct PrefixSuffix {
    PrefixSuffix() { std::cout << "prefix\n"; }
    ~PrefixSuffix() { std::cout << "suffix\n"; }
};

struct MyClass {
    void foo() { std::cout << "foo\n"; }
};


int main()
{
    Wrapper<MyClass, PrefixSuffix> w;
    w->foo();
}

Defining a PrefixSuffix class, with the prefix code inside its constructor and the suffix code inside the destructor is the way to go. Then, you can use the Wrapper class (using the -> to access to your original class' member functions) and prefix and suffix code will be executed for every call.

See it live.

Credits to this paper, where I found the solution.

share|improve this answer
    
This seems like a good answer too. I don't know enough about C++ to figure out whether yours or Quentins answer is better... :) – John 3 hours ago
    
@John Well, they both looks good to me. I think Quentin gave a more specific (but far shorter) answer; mine addresses the problem in a more general way, resulting longer, though. – Paolo M 2 hours ago
    
But why is yours better ? What can someone do using your method, which one can't do using quentins ? – John 2 hours ago
1  
@John Well, mine it's not better... It just handle the issue in a deeper way... I mean: now you have the problem of executing some prefix code to your member functions; tomorrow, you may have the problem of executing subfix code. Let's say I'm looking a bit forward ;) – Paolo M 2 hours ago
1  
@John You can have a single w->foo(); call logBefore(), then foo(), then logAfter() in sequence, the latter of which my solution does not do. Do note the caveat that, since it relies on a temporarie's lifetime, the statement bar(w->foo()); will call logBefore(), foo(), bar() then logAfter(). – Quentin 2 hours ago

You may do a wrapper, something like

class Foo {
public:
    void a() { /*...*/ }
    void b() { /*...*/ }
};

class LogFoo
{
public:
    template <typename ... Ts>
    LogFoo(Ts&&... args) : foo(std::forward<Ts>(args)...) {}

    const Foo* operator ->() const { log(); return &foo;}
    Foo* operator ->() { log(); return &foo;}
private:
    void log() const {/*...*/}
private:
    Foo foo;
};

And then use -> instead of .:

LogFoo foo{/* args...*/};

foo->a();
foo->b();
share|improve this answer

I agree on what is written on the comments of your original posts, but if you really need to do this and you don't like to use a C macro,you can add a method to call your methods.

Here is a complete example using C++ 2011 to handle correctly varying function parameters. Tested with GCC and clang

#include <iostream>

class Foo
{
        void log() {}
    public:
        template <typename R, typename... TArgs>        
        R call(R (Foo::*f)(TArgs...), const TArgs... args) {
            this->log();
            return (this->*f)(args...);
        }

        void a() { std::cerr << "A!\n"; }
        void b(int i) { std::cerr << "B:" << i << "\n"; }
        int c(const char *c, int i ) { std::cerr << "C:" << c << '/' << i << "\n"; return 0; }
};

int main() {
    Foo c;

    c.call(&Foo::a);
    c.call(&Foo::b, 1);
    return c.call(&Foo::c, "Hello", 2);
}
share|improve this answer
    
The problem with this is, outsiders calling public methods of foo, will have to know to call "call", instead of "a" or "b" directly... – John 3 hours ago
    
If you know how to do this with a C-macro, I would like to know - I'm not sure how I would do this with a macro... – John 3 hours ago
    
@John: make call() public and a(), b() private. In this way outsiders know only one function to invoke i.e call(). – sameerkn 3 hours ago
    
Your syntax is a bit broken -- a should be in place of val, and the MFP call should look like (this->*a)();. – Quentin 2 hours ago
1  
@sameerkn if outsiders don't know about a() and b(), then how will they pass call() a pointer to them.... – John 2 hours ago

Use a lambda expression and a higher-order function to avoid repetition and minimize the chance of forgetting to call log:

class Foo
{
private:
    void log(const std::string&)
    {

    }

    template <typename TF, typename... TArgs>
    void log_and_do(TF&& f, TArgs&&... xs)
    {
        log(std::forward<TArgs>(xs)...);
        std::forward<TF>(f)();
    }

public:
    void a()
    {
        log_and_do([this]
        {
            // `a` implementation...
        }, "Foo::a");
    }

    void b()
    {
        log_and_do([this]
        {
            // `b` implementation...
        }, "Foo::b");
    }
};

The benefit of this approach is that you can change log_and_do instead of changing every function calling log if you decide to alter the logging behavior. You can also pass any number of extra arguments to log. Finally, it should be optimized by the compiler - it will behave as if you had written a call to log manually in every method.


You can use a macro (sigh) to avoid some boilerplate:

#define LOG_METHOD(...) \
    __VA_ARGS__ \
    { \
        log_and_do([&]

#define LOG_METHOD_END(...) \
        , __VA_ARGS__); \
    }

Usage:

class Foo
{
private:
    void log(const std::string&)
    {

    }

    template <typename TF, typename... TArgs>
    void log_and_do(TF&& f, TArgs&&... xs)
    {
        log(std::forward<TArgs>(xs)...);
        std::forward<TF>(f)();
    }

public:
    LOG_METHOD(void a())
    {
        // `a` implementation...
    }
    LOG_METHOD_END("Foo::a");

    LOG_METHOD(void b())
    {
        // `b` implementation...
    }
    LOG_METHOD_END("Foo::b");
};
share|improve this answer
    
But then you still have to write "Log_and_do...." to each function, which is as much work as just calling log() in the first place..... The challenge is to insert the function call into each function without having to actually type out "log()" at the start of each function... – John 3 hours ago
    
@John: unfortunately there isn't any good way of "injecting" code into existing functions. A macro could help, updating my answer... – Vittorio Romeo 3 hours ago
    
But that works out to the same as manually typing log() at the start of each method right ? So we aren't avoiding any boilerplate... the challenge is how to "inject" code (as you put it), using macros or some other technique, so that we avoid having to "remember" to add the log() call to each method, or have an outsider "remember" to call some other function with a pointer to the function we really want to call... – John 3 hours ago
    
@John: the point is that there is no way of "injecting" code, not even using macros. You're either gonna need some boilerplate during method definition, or use an outsider call(...) function. – Vittorio Romeo 3 hours ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.