Function pointer oddity

Discussion in 'C++' started by Ian Collins, Aug 13, 2010.

  1. Ian Collins

    Ian Collins Guest

    This one had me going today.

    I have a class that distils down to

    template <typename T>
    struct X
    {
    mutable T t;
    };

    where T is the type of a function parameter extracted by a script. For
    one function I kept getting bizarre compiler errors like these:

    Member functions may not be declared with template type parameters.
    A function cannot be declared to be mutable.

    The hint came from g++:

    field 'X<void ()()>::t' invalidly declared function type

    It turned out one of the function's parameters was a callback typedef'd as:

    typedef void (fn)()

    Note the absent '*'. In the code it can be used interchangeably with
    fn*, but when used as a template argument, fun ensues.

    No wonder people call C's function pointer syntax crazy.

    --
    Ian Collins
     
    Ian Collins, Aug 13, 2010
    #1
    1. Advertising

  2. Ian Collins <>, on 13/08/2010 21:04:42, wrote:

    > This one had me going today.
    >
    > I have a class that distils down to
    >
    > template <typename T>
    > struct X
    > {
    > mutable T t;
    > };
    >
    > where T is the type of a function parameter extracted by a script. For
    > one function I kept getting bizarre compiler errors like these:
    >
    > Member functions may not be declared with template type parameters.
    > A function cannot be declared to be mutable.
    >
    > The hint came from g++:
    >
    > field 'X<void ()()>::t' invalidly declared function type
    >
    > It turned out one of the function's parameters was a callback typedef'd as:
    >
    > typedef void (fn)()
    >
    > Note the absent '*'. In the code it can be used interchangeably with
    > fn*, but when used as a template argument, fun ensues.


    Good to know, that was new for me.

    Just in case I'll have to stomp on it, how did you solve this issue?

    --
    FSC - http://userscripts.org/scripts/show/59948
    http://fscode.altervista.org - http://sardinias.com
     
    Francesco S. Carta, Aug 13, 2010
    #2
    1. Advertising

  3. Ian Collins

    Ian Collins Guest

    On 08/13/10 09:14 PM, Francesco S. Carta wrote:
    > Ian Collins <>, on 13/08/2010 21:04:42, wrote:
    >
    >> This one had me going today.
    >>
    >> I have a class that distils down to
    >>
    >> template <typename T>
    >> struct X
    >> {
    >> mutable T t;
    >> };
    >>
    >> where T is the type of a function parameter extracted by a script. For
    >> one function I kept getting bizarre compiler errors like these:
    >>
    >> Member functions may not be declared with template type parameters.
    >> A function cannot be declared to be mutable.
    >>
    >> The hint came from g++:
    >>
    >> field 'X<void ()()>::t' invalidly declared function type
    >>
    >> It turned out one of the function's parameters was a callback
    >> typedef'd as:
    >>
    >> typedef void (fn)()
    >>
    >> Note the absent '*'. In the code it can be used interchangeably with
    >> fn*, but when used as a template argument, fun ensues.

    >
    > Good to know, that was new for me.
    >
    > Just in case I'll have to stomp on it, how did you solve this issue?


    I haven't as yet (but I asked that the typedef be changed!). It is a
    tricky problem to solve. I originally thought of a wrapper along the
    lines of

    void f( fn ) {}
    void f( fn* ) {}

    But that won't work as the second appears as a redefinition of the first.

    --
    Ian Collins
     
    Ian Collins, Aug 13, 2010
    #3
  4. Ian Collins <>, on 13/08/2010 21:33:32, wrote:

    > On 08/13/10 09:14 PM, Francesco S. Carta wrote:
    >> Ian Collins <>, on 13/08/2010 21:04:42, wrote:
    >>
    >>> This one had me going today.
    >>>
    >>> I have a class that distils down to
    >>>
    >>> template <typename T>
    >>> struct X
    >>> {
    >>> mutable T t;
    >>> };
    >>>
    >>> where T is the type of a function parameter extracted by a script. For
    >>> one function I kept getting bizarre compiler errors like these:
    >>>
    >>> Member functions may not be declared with template type parameters.
    >>> A function cannot be declared to be mutable.
    >>>
    >>> The hint came from g++:
    >>>
    >>> field 'X<void ()()>::t' invalidly declared function type
    >>>
    >>> It turned out one of the function's parameters was a callback
    >>> typedef'd as:
    >>>
    >>> typedef void (fn)()
    >>>
    >>> Note the absent '*'. In the code it can be used interchangeably with
    >>> fn*, but when used as a template argument, fun ensues.

    >>
    >> Good to know, that was new for me.
    >>
    >> Just in case I'll have to stomp on it, how did you solve this issue?

    >
    > I haven't as yet (but I asked that the typedef be changed!). It is a
    > tricky problem to solve. I originally thought of a wrapper along the
    > lines of
    >
    > void f( fn ) {}
    > void f( fn* ) {}
    >
    > But that won't work as the second appears as a redefinition of the first.


    I understand, let us know if you find a solution that does not involve
    changing the original typedef - unfortunately I am not able to help, I
    thought about creating a macro like:

    #define fn *fn

    to be inserted before the eventual header that declares that weird
    typedef, but I'm quite sure it's a dummy attempt ;-)

    --
    FSC - http://userscripts.org/scripts/show/59948
    http://fscode.altervista.org - http://sardinias.com
     
    Francesco S. Carta, Aug 13, 2010
    #4
  5. Ian Collins

    Ian Collins Guest

    On 08/13/10 09:45 PM, Francesco S. Carta wrote:
    > Ian Collins <>, on 13/08/2010 21:33:32, wrote:
    >
    >> On 08/13/10 09:14 PM, Francesco S. Carta wrote:
    >>>
    >>> Just in case I'll have to stomp on it, how did you solve this issue?

    >>
    >> I haven't as yet (but I asked that the typedef be changed!). It is a
    >> tricky problem to solve. I originally thought of a wrapper along the
    >> lines of
    >>
    >> void f( fn ) {}
    >> void f( fn* ) {}
    >>
    >> But that won't work as the second appears as a redefinition of the first.

    >
    > I understand, let us know if you find a solution that does not involve
    > changing the original typedef - unfortunately I am not able to help, I
    > thought about creating a macro like:
    >
    > #define fn *fn
    >
    > to be inserted before the eventual header that declares that weird
    > typedef, but I'm quite sure it's a dummy attempt ;-)


    Actually the solution turns out to be a no-brainer.

    My code generates a test (test::function()) version of the library
    function and a wrapper to call it. As the offending template is in the
    test function declaration, I just changed it to use a fn* and hand wrote
    the wrapper.

    --
    Ian Collins
     
    Ian Collins, Aug 13, 2010
    #5
  6. Ian Collins <>, on 13/08/2010 21:53:48, wrote:

    > On 08/13/10 09:45 PM, Francesco S. Carta wrote:
    >> Ian Collins <>, on 13/08/2010 21:33:32, wrote:
    >>
    >>> On 08/13/10 09:14 PM, Francesco S. Carta wrote:
    >>>>
    >>>> Just in case I'll have to stomp on it, how did you solve this issue?
    >>>
    >>> I haven't as yet (but I asked that the typedef be changed!). It is a
    >>> tricky problem to solve. I originally thought of a wrapper along the
    >>> lines of
    >>>
    >>> void f( fn ) {}
    >>> void f( fn* ) {}
    >>>
    >>> But that won't work as the second appears as a redefinition of the
    >>> first.

    >>
    >> I understand, let us know if you find a solution that does not involve
    >> changing the original typedef - unfortunately I am not able to help, I
    >> thought about creating a macro like:
    >>
    >> #define fn *fn
    >>
    >> to be inserted before the eventual header that declares that weird
    >> typedef, but I'm quite sure it's a dummy attempt ;-)

    >
    > Actually the solution turns out to be a no-brainer.
    >
    > My code generates a test (test::function()) version of the library
    > function and a wrapper to call it. As the offending template is in the
    > test function declaration, I just changed it to use a fn* and hand wrote
    > the wrapper.


    Sorry if I point out something dummy once more, but you always write
    that as "fn*", shouldn't that be always "*fn"? (if not simply "fn()" in
    the actual call)

    Anyway, I'm not sure I understand how exactly you implemented it, could
    you paste a snippet illustrating the final result?

    That would ease my comprehension (as well other's, if somebody else
    happens to have the same difficulty in working out the actual code).

    --
    FSC - http://userscripts.org/scripts/show/59948
    http://fscode.altervista.org - http://sardinias.com
     
    Francesco S. Carta, Aug 13, 2010
    #6
  7. Ian Collins

    Ian Collins Guest

    On 08/13/10 10:06 PM, Francesco S. Carta wrote:
    > Ian Collins <>, on 13/08/2010 21:53:48, wrote:
    >
    >> On 08/13/10 09:45 PM, Francesco S. Carta wrote:
    >>> Ian Collins <>, on 13/08/2010 21:33:32, wrote:
    >>>
    >>>> On 08/13/10 09:14 PM, Francesco S. Carta wrote:
    >>>>>
    >>>>> Just in case I'll have to stomp on it, how did you solve this issue?
    >>>>
    >>>> I haven't as yet (but I asked that the typedef be changed!). It is a
    >>>> tricky problem to solve. I originally thought of a wrapper along the
    >>>> lines of
    >>>>
    >>>> void f( fn ) {}
    >>>> void f( fn* ) {}
    >>>>
    >>>> But that won't work as the second appears as a redefinition of the
    >>>> first.
    >>>
    >>> I understand, let us know if you find a solution that does not involve
    >>> changing the original typedef - unfortunately I am not able to help, I
    >>> thought about creating a macro like:
    >>>
    >>> #define fn *fn
    >>>
    >>> to be inserted before the eventual header that declares that weird
    >>> typedef, but I'm quite sure it's a dummy attempt ;-)

    >>
    >> Actually the solution turns out to be a no-brainer.
    >>
    >> My code generates a test (test::function()) version of the library
    >> function and a wrapper to call it. As the offending template is in the
    >> test function declaration, I just changed it to use a fn* and hand wrote
    >> the wrapper.

    >
    > Sorry if I point out something dummy once more, but you always write
    > that as "fn*", shouldn't that be always "*fn"? (if not simply "fn()" in
    > the actual call)


    Oops, I didn't see your reply. "fn*" is a pointer to type fn, "*fn" is
    a function pointer type.

    > Anyway, I'm not sure I understand how exactly you implemented it, could
    > you paste a snippet illustrating the final result?


    Well my code, which is used to generate mocks of library functions for
    testing, generates a declaration for the mock function and wrapper
    definition of the original function which calls the mock. Take sleep()
    for example; the declaration is:

    namespace test {
    typedef OneParameterFunction<sleepId,unsigned,unsigned> sleep;
    }

    and the definition is:

    int sleep(unsigned p0) { return test::sleep(p0); }

    The declaration and definition are generated by macros (cough).

    So all I had to do was use the declaration macro with the parameter type
    of fn* and manually add the stub to match the true header declaration.

    --
    Ian Collins
     
    Ian Collins, Aug 15, 2010
    #7
  8. Ian Collins <>, on 15/08/2010 11:19:41, wrote:

    > On 08/13/10 10:06 PM, Francesco S. Carta wrote:
    >> Ian Collins <>, on 13/08/2010 21:53:48, wrote:
    >>
    >>> On 08/13/10 09:45 PM, Francesco S. Carta wrote:
    >>>> Ian Collins <>, on 13/08/2010 21:33:32, wrote:
    >>>>
    >>>>> On 08/13/10 09:14 PM, Francesco S. Carta wrote:
    >>>>>>
    >>>>>> Just in case I'll have to stomp on it, how did you solve this issue?
    >>>>>
    >>>>> I haven't as yet (but I asked that the typedef be changed!). It is a
    >>>>> tricky problem to solve. I originally thought of a wrapper along the
    >>>>> lines of
    >>>>>
    >>>>> void f( fn ) {}
    >>>>> void f( fn* ) {}
    >>>>>
    >>>>> But that won't work as the second appears as a redefinition of the
    >>>>> first.
    >>>>
    >>>> I understand, let us know if you find a solution that does not involve
    >>>> changing the original typedef - unfortunately I am not able to help, I
    >>>> thought about creating a macro like:
    >>>>
    >>>> #define fn *fn
    >>>>
    >>>> to be inserted before the eventual header that declares that weird
    >>>> typedef, but I'm quite sure it's a dummy attempt ;-)
    >>>
    >>> Actually the solution turns out to be a no-brainer.
    >>>
    >>> My code generates a test (test::function()) version of the library
    >>> function and a wrapper to call it. As the offending template is in the
    >>> test function declaration, I just changed it to use a fn* and hand wrote
    >>> the wrapper.

    >>
    >> Sorry if I point out something dummy once more, but you always write
    >> that as "fn*", shouldn't that be always "*fn"? (if not simply "fn()" in
    >> the actual call)

    >
    > Oops, I didn't see your reply. "fn*" is a pointer to type fn, "*fn" is a
    > function pointer type.
    >
    >> Anyway, I'm not sure I understand how exactly you implemented it, could
    >> you paste a snippet illustrating the final result?

    >
    > Well my code, which is used to generate mocks of library functions for
    > testing, generates a declaration for the mock function and wrapper
    > definition of the original function which calls the mock. Take sleep()
    > for example; the declaration is:
    >
    > namespace test {
    > typedef OneParameterFunction<sleepId,unsigned,unsigned> sleep;
    > }
    >
    > and the definition is:
    >
    > int sleep(unsigned p0) { return test::sleep(p0); }
    >
    > The declaration and definition are generated by macros (cough).
    >
    > So all I had to do was use the declaration macro with the parameter type
    > of fn* and manually add the stub to match the true header declaration.


    Thank you for the further explanations.

    By the way, I find nothing lamentable in using macros for generating
    lots of patterned code, that kind of automation is also meant to save us
    some good time in cases like this :)

    --
    FSC - http://userscripts.org/scripts/show/59948
    http://fscode.altervista.org - http://sardinias.com
     
    Francesco S. Carta, Aug 15, 2010
    #8
  9. Ian Collins

    James Kanze Guest

    On Aug 13, 10:04 am, Ian Collins <> wrote:
    > This one had me going today.


    > I have a class that distils down to


    > template <typename T>
    > struct X
    > {
    > mutable T t;
    > };


    > where T is the type of a function parameter extracted by
    > a script. For one function I kept getting bizarre compiler
    > errors like these:


    > Member functions may not be declared with template type
    > parameters. A function cannot be declared to be mutable.


    > The hint came from g++:


    > field 'X<void ()()>::t' invalidly declared function type


    > It turned out one of the function's parameters was a callback
    > typedef'd as:


    > typedef void (fn)()


    > Note the absent '*'. In the code it can be used
    > interchangeably with fn*,


    Only in a few specific cases. In this respect, function types
    work a lot like array types: functions auto-convert to pointers
    to functions in most contexts (even more contexts than arrays,
    in fact), and a function parameter or return type declared as
    a function is considered to be declared as a pointer to
    function. (I seem to remember that return types are rewritten
    as well, but I can't find the text in the standard at the
    moment.) Note however that given the typedef above,
    fn func;
    is the equivalent of:
    void func();
    and not:
    void (*func)();
    And
    void setCallback(fn& );
    requires a function, and not a pointer to a function.

    And as you noticed, when fn is used as a type argument to
    a template, it is a function, and not a pointer.

    > but when used as a template argument, fun ensues.


    > No wonder people call C's function pointer syntax crazy.


    No crazier than any of the rest of the declaration syntax. The
    problem is the implicit conversions, and especially the rewrite
    of function argument types. What's anomolous is that given the
    above typedef:
    void setCallback(fn callback);
    works (and takes a pointer to a function).

    --
    James Kanze
     
    James Kanze, Aug 17, 2010
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Smeckler
    Replies:
    4
    Views:
    362
    Alf P. Steinbach
    Jul 28, 2003
  2. glen stark
    Replies:
    2
    Views:
    716
    Ron Natalie
    Oct 10, 2003
  3. Sheila King

    Oddity with function default arguments

    Sheila King, Jun 12, 2004, in forum: Python
    Replies:
    2
    Views:
    281
    Heiko Wundram
    Jun 12, 2004
  4. Replies:
    4
    Views:
    287
    Mike Wahler
    Jan 2, 2007
  5. Replies:
    5
    Views:
    212
    Michael Winter
    May 24, 2005
Loading...

Share This Page