5

I want to have a class that would be able to keep as its fields a pointer to a function and a pointer to a structure holding is arguments. The interface of that object would be a method call() taking no arguments but passing saved arguments to the above mentioned function. A family of such classes for different arguments types and counts would have a common abstract ancestor with call being virtual.

As for now I have the following code which works, though adding the -pedantic option to g++ yields errors:

class Function {
    protected:
    void *data;
    void *function;
    public:
    virtual void call() = 0;
};

class SingleArgumentFunction : public Function {
    public:
    SingleArgumentFunction( void (*f)(int), int i ) {
        int *icpy = new int(i);
        function = (void*) f;
        data = (void*) icpy;
    }
    ~SingleArgumentFunction() { delete (int*)data; }
    inline void call() {
        ( *((void (*)(int))function) )( *(int*)data );
    }
};

The error I get is as the title says:

warning: ISO C++ forbids casting between pointer-to-function and pointer-to-object

How to handle that?

yauser
  • 707
  • 2
  • 8
  • 19

2 Answers2

10

Don't cast pointer-to-function to pointer-to-object, they are not guaranteed to have the same size. You will be able to work around this issue by using a void(*)() function pointer instead.

C99 [6.2.5/27]:

A pointer to void shall have the same representation and alignment requirements as a pointer to a character type. Similarly, pointers to qualified or unqualified versions of compatible types shall have the same representation and alignment requirements. All pointers to structure types shall have the same representation and alignment requirements as each other. All pointers to union types shall have the same representation and alignment requirements as each other. Pointers to other types need not have the same representation or alignment requirements.

C99 [6.3.2.3/8]:

A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer.

References taken from this other SO answer.


By the way, it seems that you are trying to recreate std::function+std::bind.

std::function< void() > f;
f = std::bind( &some_function_that_takes_an_int, 42 );

f(); // look ma! no arguments
Community
  • 1
  • 1
K-ballo
  • 80,396
  • 20
  • 159
  • 169
  • I haven't used std::function yet, though after taking a glimpse at the documentation I can't see how would it serve my case as I seem to need to state precisely there what arguments my function is to take, while I want my class to be independent from that. – yauser Jan 27 '13 at 02:30
  • 2
    @yauser: You would use it in conjunction with `std::bind`. `std::function f = std::bind( &your_function, your_arguments... ); f();` – K-ballo Jan 27 '13 at 02:33
  • why would those be different? isn't a pointer just a memory adress? – yauser Jan 27 '13 at 02:57
  • 2
    @yauser: You mean functions and objects? No, they may not always be just a memory address. And if my memory serves me right, pointers to different types may have different sizes as well. Although if that's right then `void*` would have to be big enough to accommodate the biggest of them... I should go back to the standard – K-ballo Jan 27 '13 at 03:00
  • Thank you very much for such an exhaustive answer! Both of your solutions work and you've corrected my understanding of the pointer implementation. So thankful! :) – yauser Jan 27 '13 at 03:12
  • 1
    @K-ballo +1, your understanding is correct, especially on embedded systems where the size of *data* pointers can often be significantly different than the size of a *code* pointer. Wind the clock back far enough and it was also true in the mixed memory models of the DOS-based architectures. – WhozCraig Jan 27 '13 at 03:41
4

If you are forced to use an API that wants a function pointer as void*, you can prefix the statement which generates the warning with __extension__ to silence that warning. Since it's gcc-specific, it's best to guard that word, i.e.:

#ifdef __GNUC__
__extension__
#endif
the_statement_that_includes_the_cast;

From http://trac.osgeo.org/qgis/ticket/234.

Oak
  • 26,231
  • 8
  • 93
  • 152