Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass Virtually Anything To A Function In C++ (or C)?

I need to pass something like a pointer that takes anything as a function parameter. You know, something without any predefined type or a type that can take anything like this:

 void MyFunc( *pointer ); 

And then use it like:

char * x = "YAY!";
MyFunc(x);

int y = 10;
MyFunc(&y);

MyObj *b = new MyObj();
MyFunc(b);

And I don't want to use templates because I am mostly using C in my project. Is there anything that can be used here except a function macro?

like image 923
ApprenticeHacker Avatar asked Nov 30 '22 16:11

ApprenticeHacker


1 Answers

In C++, Boost.Any will let you do this in a type-safe way:

void func(boost::any const &x)
{
    // any_cast a reference and it
    // will throw if x is not an int.
    int i = any_cast<int>(x);

    // any_cast a pointer and it will
    // return a null pointer if x is not an int.
    int const *p = any_cast<int>(&x);
}

// pass in whatever you want.
func(123);
func("123");

In C, you would use a void pointer:

void func(void const *x)
{
    // it's up to you to ensure x points to an int.  if
    // it's not, it might crash or it might silently appear
    // to work. nothing is checked for you!
    int i = *(int const*)x;
}

// pass in whatever you want.

int i = 123;
func(&i);

func("123");

You seem adverse to it but I'll recommend it anyway: if you're using C++, embrace it. Don't be afraid of templates. Things like Boost.Any and void pointers have a place in C++, but it is very small.

Update:

Well , I am making a small signals - slots - connections library to be used with my gui toolkit. So that I can get rid of the Ugly WNDPROC. I need these pointers for the connections.

If you need multi-target signals, Boost.Signals already provides a full and tested signals/slots implementation. You can use Boost.Bind (or std::bind, if you've got a C++0x compiler) to connect member functions:

struct button
{
    boost::signal<void(button&)> on_click;
}

struct my_window
{
    button b;

    my_window()
    {
        b.on_click.connect(std::bind(&my_window::handle_click,
                                     this, std::placeholders::_1));
    }

    void handle_click(button &b)
    {
    }

    void simulate_click()
    {
        b.on_click(b);
    }
};

If you only want a simple callback, Boost.Function (or std::function if you've got a C++0x compiler) will work well:

struct button
{
    std::function<void(button&)> on_click;
}

struct my_window
{
    button b;

    my_window()
    {
        b.on_click = std::bind(&my_window::handle_click,
                               this, std::placeholders::_1);
    }

    void handle_click(button &b)
    {
    }

    void simulate_click()
    {
        b.on_click(b);
    }
};
like image 120
Cory Nelson Avatar answered Dec 15 '22 06:12

Cory Nelson