c++templatesgenericsvariadic-templatestypelist

Generic C++ function wrapping


I am tying to write a simple generic smart pointer template that allows a programmer to apply an arbitrary number of wraps before and after calling some function FUNC() e.g. If a requirement was to start timer, lock, log_start, FUNC(), log_end, unlock , stop timer

Then I would like to be able to write something simple where the programmer supplied 3 types and a function to a template and let the compiler do the rest. I get the feeling it can be done using variadic templates in a manner similar to how typelists worked combined with overloading operator ->

i.e.

class timer {}; // ctor start timer, dtor stop timer
class locker{}; // ctor lock, dtor unlock
class logger{}; // ctor lock, dtor unlock

Then some code such as

template <typename ...base_class_list> 
class aggregate : public base_class_list... {};
using pre_conditions = aggregate<logger, locker, trans>;

class gadget 
{
    auto do_something() -> void;
}; // gadget

Finally (the part I would like to write but don’t know how to glue it together

SMART_PTR<pre_conditions, gadget> g;
g->do_something();

I can get it working easily enough using the approach described by Bjarne Stroustrup in “Wrapping C++ Member Function Calls”, but was wondering if there was a more generic and elegant solution.


Solution

  • The easy way is to wrapping only all operator():

    template <typename T, typename ... Ts>
    struct magic
    {
        T obj;
    
        template <typename ... Us>
        decltype(auto) operator ()(Us...args)
        {
            ordered_tuple<Ts...> t; // tuple doesn't guaranty order
            obj(std::forward<Us>(args)...);
        }
    };
    

    Demo

    To wrap operator ->, it is more tricky:

    template <typename T, typename ... Ts>
    class wrapper
    {
        ordered_tuple<Ts...> t; // tuple doesn't guaranty order
        T* obj;
    public:
        wrapper(T* obj) : obj(obj) {}
    
        T* operator ->()
        {
            return obj;
        }
    };
    
    template <typename T, typename ... Ts>
    class magic
    {
        T obj;
    public:
        wrapper<T, Ts...> operator ->()
        {
            return {&obj};
        }
    };
    

    Demo

    Handling const and non-default constructor should also be done. (and finding better name).