Generic Pointer Type

  • Thread starter Frederick Gotham
  • Start date
F

Frederick Gotham

For objects, we have "void*" as the generic pointer type. For instance:

enum ParamType { Int, Double };

void Func(void *const p,ParamType const pt)
{
switch (pt)
{
case Int: *(int*)p = 42; break;
case Double: *(double*)p = 42; break;
}
}

However, we're not so lucky when it comes to function pointer types. The
behaviour of the following snippet is undefined:

enum ParamType { Int, Double };

void Func(void *const p,ParamType const pt)
{
switch (pt)
{
case Int: ((void(*)(int))p)(42); break;
case Double: ((void(*)(double))p)(42); break;
}
}

I thought I might go about writing a class which would serve as a generic
function pointer. As this was just a pet project, I thought I'd make its
behaviour as well-defined as possible (to the extreme just for the craic!).
I'm designing the class in such a way that it should behave exactly like an
intrinsic function pointer type. I've also taken some liberties in writing
the code, e.g. the behaviour is undefined if you assign from an
uninitialised FuncPtr object. Here's what I've got at the moment:

#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <new>

class FuncPtr {
private:

std::size_t quant; /* Size in bytes of function pointer */
void *pbytes;

public:

FuncPtr() : pbytes() {}

template<class T>
FuncPtr(T const p) : quant(sizeof p)
{
pbytes = std::malloc(quant);
if (!pbytes) throw std::bad_alloc();

std::memcpy(pbytes,&p,quant);
}

FuncPtr(FuncPtr const &a) : quant(a.quant)
{
pbytes = std::malloc(quant);
if (!pbytes) throw std::bad_alloc();

std::memcpy(pbytes,a.pbytes,quant);
}

FuncPtr &operator=(FuncPtr const &a)
{
quant = a.quant;

pbytes = std::realloc(pbytes,quant);
if (!pbytes) throw std::bad_alloc();

std::memcpy(pbytes,a.pbytes,quant);

return *this;
}

~FuncPtr() { free(pbytes); }

template<class T>
operator T() const
{
return *(T*)pbytes;
}
};

enum ParamType { Int, Double };

void Foo(FuncPtr const p,ParamType const pt)
{
switch (pt)
{
case Int: ((void(*)(int))p)(5); break;
case Double: ((void(*)(double))p)(5); break;
}
}

#include <iostream>
#include <ostream>

void FuncI(int) { std::cout << "Int function called" << std::endl; }
void FuncD(double) { std::cout << "Double function called" << std::endl; }

int main()
{
FuncPtr a;
FuncPtr const b = FuncD;

a = b;

Foo(a,Double);

Foo(FuncI,Int);
}


I realise it's a bit much to use dynamic memory allocation, but it's sort
of the only way I could _guarantee_ the correct alignment and size (short
of playing around with unions and what have you).

Anywho I just thought I'd throw that out there to see what kind of
responses I get.
 
F

Frederick Gotham

Frederick Gotham:
template<class T>
operator T() const
{
return *(T*)pbytes;
}


That would be more politically correct as:

return *(T const*)pbytes;

(although it doesn't make a difference).
 
N

Noah Roberts

Frederick said:
I thought I might go about writing a class which would serve as a generic
function pointer. As this was just a pet project, I thought I'd make its
behaviour as well-defined as possible (to the extreme just for the craic!).
I'm designing the class in such a way that it should behave exactly like an
intrinsic function pointer type. I've also taken some liberties in writing
the code, e.g. the behaviour is undefined if you assign from an
uninitialised FuncPtr object.

Not to rain on your parade man but boost has this already. Check out
the function library. It will be in the next C++ standard and works
with things like bind, lambda, and all the algorithms in the std lib.
It's a pretty good wheel. Your time might be spent better on something
else.
 
N

Noah Roberts

Noah said:
Not to rain on your parade man but boost has this already. Check out
the function library. It will be in the next C++ standard and works
with things like bind, lambda, and all the algorithms in the std lib.
It's a pretty good wheel. Your time might be spent better on something
else.

Here's your original problem solved with boost::function:


#include <iostream>
#include <boost/any.hpp>

#include <boost/function.hpp>

void f1(int x) { std::cout << "void f1(int).\n"; }
void f2(double x) { std::cout << "void f2(double).\n"; }
int f3(double x) { std::cout << "int f3(double).\n"; return
static_cast<int>(x); }

void Func(boost::function<void (int)> const & f)
{
f(42);
}

struct functor
{
void operator() (int x) { std::cout << "void functor::()(int).\n"; }
};

int main()
{
boost::function<void (int)> f;

f = &f1;
Func(f);

f = &f2;
Func(f);

f = &f3;
Func(f);

Func(&f3);

functor fun;
Func(fun);

int y; std::cin >> y;
return 0;
}

f can be assigned any invocable object that can be called with an int
as parameter and returns an object convertable to void. Func can be
used the same.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top