Cool C++0X features VII: A variadic wrapper solution

Post by Nico Brailovsky @ 2011-05-24 | Permalink | Leave a comment

Last time we were trying to build a wrapper function, in which we don't control the class being wrapped nor the user of the wrapper (meaning we can't change either of those but they could change without warning).

This was the first approach:

#include 
void do_something() { std::cout << PRETTY_FUNCTION << "n"; }
void wrap() {
    std::cout << PRETTY_FUNCTION << "n";
    do_something();
}
int main() {
    wrap();
    return 0;
}

Yet, as we saw, it's not scalable, when either part changes the whole things break. We proposed then a variadic template solution, which, if you tried it yourself, should look something like this:

#include 
void do_something() { std::cout << PRETTY_FUNCTION << "n"; }
void do_something(const char*) { std::cout << PRETTY_FUNCTION << "n"; }
template 
void wrap(Args... a) {
    std::cout << PRETTY_FUNCTION << "n";
    do_something(a...);
}
int main() {
    wrap();
    wrap("nice");
    return 0;
}

That's better. Now we don't care about which parameters do_something should get, nor how many of them are there supposed to be, just how it's called. If you read the previous entries on variadic templates this should be a walk in the park. It still has a flaw though: we need to know the return type of do_something!

Is there a way to write a wrapper without knowing the return type of a function you are wrapping? Yes, in Ruby you can. But now you can do it in C++0x too, and we'll see how to do it next time.

A closing remark: You could do something like this wrapping everything in a class:

#include 
struct Foo {
    void do_something() { std::cout << PRETTY_FUNCTION << "\n"; }
    void do_something(const char*) { std::cout << PRETTY_FUNCTION << "\n"; }
};
template
struct Wrapper : public Base {
    template 
    void wrap(Args... a) {
        std::cout << PRETTY_FUNCTION << "n";
        Base::do_something(a...);
    }
};
int main() {
    Wrapper w;
    w.wrap();
    w.wrap("nice");
    return 0;
}

The above works just fine, but due to some limitations in the current (stable) version of gcc we will use the former version (the problem with this form will be clear later, I promise).