My current project requires quite a bit of function pointer passing to guarantee the flexibility desired. Given how messy and annoying I find functions pointers to be I decided to create a wrapper class listed below. Works fine, however it would be nice if their was a method so I could input the variables in an infinite list (well you know within reason) like a vaarg list.

I only have a basic understanding of templates so any help or suggestions would be appreciated. Honestly I rarely write a function with more than 4-5 input parameters so I could just go the extra mile and finish doing this but seems there should be a better way.

#ifndef FUNCTION_HANDLER_H
#define FUNCTION_HANDLER_H
//*********************************************
//Function Pointer Wrapper Class 
//*********************************************
template<typename return_type,typename variable0, typename variable1 = void, typename variable2 = void>
class Function_Handler
{
protected:
	return_type (*m_Function)(variable0,variable1,variable2);
public:
	void set_function(return_type (*foo)(variable0,variable1,variable2)){m_Function = foo;}
	return_type call_function(variable0 m, variable1 n, variable2 o){if(m_Function != nullptr)m_Function(m,n,o)else std::runtime_error("Function_Handler must be initialized");}
	void clear(){m_Function = nullptr;}
	Function_Handler(return_type (*foo)(variable0,variable1,variable2)){m_Function = foo;}
	Function_Handler(){m_Function = nullptr;}
}; 
//*************************************************
//Specialization for only one variable
//*************************************************
template<typename return_type,typename variable0>
class Function_Handler<return_type,variable0,void,void>
{
protected:
	return_type (*m_Function)(variable0);
public:
	void set_function(return_type(*foo)(variable0)){m_Function = foo;}
	return_type call_function(variable0 m){if(m_Function != nullptr)m_Function(m,n,o)else std::runtime_error("Function_Handler must be initialized");}
	void clear(){m_Function = nullptr;}
	Function_Handler(return_type (*foo)(variable0)){m_Function = foo;}
	Function_Handler(){m_Function = nullptr;}
};
//************************************************
//Specialization for two variables
//************************************************
template<typename return_type,typename variable0, typename variable1 = void>
class Function_Handler<return_type,variable0,variable1,void>
{
protected:
	return_type (*m_Function)(variable0,variable1);
public:
	void set_function(return_type(*foo)(variable0,variable1)){m_Function = foo;}
	return_type call_function(variable0 m,variable1 n){if(m_Function != nullptr)m_Function(m,n,o)else std::runtime_error("Function_Handler must be initialized");}
	void clear(){m_Function = nullptr;}
	Function_Handler(return_type (*foo)(variable0,variable1)){m_Function = foo;}
	Function_Handler(){m_Function = nullptr;}
};

#endif

Dani AI

Generated

Short summary and practical update: wanted a typed wrapper that can accept a variable number of arguments. As pointed out, the modern solution is to use variadic templates; correctly suggested Boost when you need C++98 compatibility. Below is a concise, practical approach you can apply now and that reads well years later.

A compact, type-safe wrapper that works with any callable (function pointer, lambda, functor) uses std::function plus a parameter pack. It keeps the interface simple and delegates storage/type-erasure to the standard library.

#include <functional>
#include <stdexcept>
#include <utility>

template<typename R, typename... Args>
class FunctionHandler {
    std::function<R(Args...)> fn;
public:
    FunctionHandler() = default;
    FunctionHandler(std::function<R(Args...)> f): fn(std::move(f)) {}
    void set(std::function<R(Args...)> f) { fn = std::move(f); }
    R call(Args... args) {
        if (!fn) throw std::bad_function_call();
        return fn(std::forward<Args>(args)...);
    }
    void clear() { fn = nullptr; }
};

Notes, tradeoffs and fallbacks:

  • If your toolchain supports C++11/C++14/C++17, prefer the std::function + variadic-template pattern for clarity and flexibility. See the language reference for parameter packs and std::function for details (variadic templates, std::function).
  • For older MSVC/compilers without variadic templates, use Boost.Function/Boost.Bind or provide explicit overloads for the small range of arities you need. Avoid C-style va_arg for typed dispatch.
  • std::function uses type erasure and has measurable overhead. For tight hot paths, keep the callable as a template parameter (no std::function) to allow inlining and zero-overhead calls.
  • To bind member functions or create pre-bound callables, use std::bind or lambdas (std::bind).

If using Visual Studio, check current compiler docs for variadic template support rather than relying on the 2011-era status ().

Recommended Answers

All 4 Replies

Aren't you just a lucky duck. This feature is part of the new C++0x standard as variadic templates:

#include <iostream>
#include <stdexcept>
#include <string>

template <typename ReturnType, typename... Args>
class Function_Handler {
    typedef ReturnType (*fun_t)(Args...);
protected:
    fun_t m_Function;
public:
    Function_Handler(fun_t foo) { m_Function = foo; }
    Function_Handler() { m_Function = nullptr; }

    void set(fun_t foo) { m_Function = foo; }
    void clear() { m_Function = nullptr; }

    ReturnType call(Args... args)
    {
        if (m_Function != nullptr)
            return m_Function(args...);
        else
            std::runtime_error("Function_Handler must be initialized");
            
        return ReturnType();
    }
};

int main()
{
    Function_Handler<void, double> a([](double a) {
        std::cout << a << '\n';
    });
    Function_Handler<int, int, int> b([](int a, int b) -> int {
        std::cout << a << " + " << b << " = ";
        return a + b;
    });
    Function_Handler<void, std::string, int, int> c([](std::string prefix, int a, int b) {
        std::cout << prefix << ": " << a << ' ' << b << '\n';
    });

    a.call(123.456);
    std::cout << b.call(1, 2) << '\n';
    c.call("Tada", 11, 22);
}

Prior to C++, you'd indeed have to write a case for each argument count you expect, and more than expected are just out of luck.

As said, the new C++ standard solves your implementation problem with the new feature of variadic templates. However, there is also a solution that solves the problem you made your class for. The library called Boost.Bind (which is also now part of the new standard) was made for that purpose, and, since it is C++98 compliant, it does actually hide, under-the-hood, a series of overloads for all the different numbers of parameters (up to 10).

Ahhhhh visual studio doesn't seem to support this feature yet. Man seems really useful. Lots of examples were very interesting when I was reading about them.

I might try the boost version out than since I already use it for a few things. Thanks.

Ahhhhh visual studio doesn't seem to support this feature yet.

From what I hear, variadic templates are on the top of the list for C++0x features to include in the next release of Visual Studio. With any luck, the other features I consider essential will be added too. ;)

Man seems really useful.

Powerful, sure. Useful, definitely. Obscure and likely to be a cause of frustration? Most certainly. On the plus side, the language specification for variadic templates is short and sweet (be thankful for small blessings). So at the very least we don't have to root through hundreds of pages of dense language lawyerese like when templates were standardized. :icon_rolleyes:

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.