J. Smith
J. Smith

Reputation: 35

Class template based wrapping function

Let's assume we have to use several versions of the same old-style interface which consists of a set of functions. The difference between versions is in the naming convention and additional commonly used last argument in each function that we need to process after each function invocation. Something like

bool f1_v1(double a, int *common_arg);
// .....

bool fN_v1(double a, bool b, char c, int *common_arg);

Simple template based wrap looks like

template <typename T> struct wrapper;

template<typename _Res, typename... _ArgTypes>
struct wrapper<_Res(_ArgTypes...)> {

    template <_Res (*f)(_ArgTypes...)>
    struct wrap {

        template <typename... Args> 
        _Res operator()(Args... args) {
            int common_arg;
            _Res res = f(args..., &common_arg);
            // common processing....
// .....

            return res;
        };
    };
};

wrapper<decltype(f1_v1)>::wrap<f1_v1> _f1;
// .....

wrapper<decltype(fN_v1)>::wrap<fN_v1> _fN;

It looks ugly, isn't it? And we still need macro to avoid double substitution of the function name. Is there an elegant solution for this?

Upvotes: 1

Views: 301

Answers (1)

max66
max66

Reputation: 66200

At the moment, C++11 or C++14, I think you can only semplify the wrapper class, avoiding the inner wrap struct, using partial specialization as follows

template <typename T, T>
struct wrapper;

template <typename _Res, typename... _ArgTypes, _Res (*f)(_ArgTypes...)>
struct wrapper<_Res(_ArgTypes...), f>
 {
   template <typename... Args> 
      _Res operator()(Args... args)
       {
         int common_arg;
         _Res res = f(args..., &common_arg);
         // common processing....

         return res;
       };
 };

So you can define and use _f1 and _fN as follows

wrapper<decltype(f1_v1), f1_v1> _f1;
wrapper<decltype(fN_v1), fN_v1> _fN;

std::cout << _f1(0.1) << std::endl;
std::cout << _fN(0.1, true, 'c') << std::endl;

If you want define _f1 and _fN as follows

wrapper<f1_v1> _f1;
wrapper<fN_v1> _fN;

you need a C++17 compliant compiler and the auto type for non-type template argument.

I don't have a C++17 compiler but I suppose that wrapper should be defined as follows

template <auto f>
struct wrapper
 {
   template <typename... Args> 
      _Res operator()(Args... args)
       {
         int common_arg;
         _Res res = f(args..., &common_arg);
         // common processing....

         return res;
       };
 };

Upvotes: 1

Related Questions