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

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.