Function versus pointer to function, in context of std::function,huh?

Discussion in 'C++' started by Alf P. Steinbach, Jul 25, 2011.

  1. When I do this:

    typedef function< void( Type const& ) > DestroyFunc;

    then Visual C++ 10.0 is happy.

    But when I do this:

    typedef function< void(*)( Type const& ) > DestroyFunc;

    then it spews out a long sequence of silly error messages, like


    <sillyErrorMessages>
    1>c:\program files (x86)\microsoft visual studio
    10.0\vc\include\functional(94): error C2027: use of undefined type
    'std::tr1::_Get_function_impl<_Tx>'
    1> with
    1> [
    1> _Tx=void (__cdecl *)(const int &)
    1> ]
    1> d:\dev\utility\clear_rounded_corners\cppx\owned.h(35) : see
    reference to class template instantiation 'std::tr1::function<_Fty>'
    being compiled
    1> with
    1> [
    1> _Fty=void (__cdecl *)(const int &)
    1> ]
    1> d:\dev\utility\clear_rounded_corners\main.cpp(283) : see
    reference to class template instantiation 'cppx::Owned<Type>' being compiled
    1> with
    1> [
    1> Type=int
    1> ]
    1>c:\program files (x86)\microsoft visual studio
    10.0\vc\include\functional(95): error C2504: '_Type' : base class undefined
    1>c:\program files (x86)\microsoft visual studio
    10.0\vc\include\functional(98): error C2027: use of undefined type
    'std::tr1::_Get_function_impl<_Tx>'
    1> with
    1> [
    1> _Tx=void (__cdecl *)(const int &)
    1> ]
    1>c:\program files (x86)\microsoft visual studio
    10.0\vc\include\functional(98): error C2146: syntax error : missing ';'
    before identifier '_Mybase'
    1>c:\program files (x86)\microsoft visual studio
    10.0\vc\include\functional(98): error C4430: missing type specifier -
    int assumed. Note: C++ does not support default-int
    1>c:\program files (x86)\microsoft visual studio
    10.0\vc\include\functional(98): error C4430: missing type specifier -
    int assumed. Note: C++ does not support default-int
    </sillyErrorMessages>


    What? Isn't that function type decaying to pointer to function type? And
    if it isn't, shouldn't std::function be able to tackle pointer to
    function type?


    Cheers, & just wondering,

    - Alf
    Alf P. Steinbach, Jul 25, 2011
    #1
    1. Advertising

  2. Alf P. Steinbach

    Noah Roberts Guest

    On 7/25/2011 5:50 AM, Alf P. Steinbach wrote:
    > When I do this:
    >
    > typedef function< void( Type const& ) > DestroyFunc;
    >
    > then Visual C++ 10.0 is happy.
    >
    > But when I do this:
    >
    > typedef function< void(*)( Type const& ) > DestroyFunc;
    >
    > then it spews out a long sequence of silly error messages, like
    >

    ....
    > What? Isn't that function type decaying to pointer to function type?


    Nope.

    And
    > if it isn't, shouldn't std::function be able to tackle pointer to
    > function type?


    void whatever(Type const&);

    function<void(Type const&)> fun = &whatever;
    Noah Roberts, Jul 25, 2011
    #2
    1. Advertising

  3. Alf P. Steinbach

    SG Guest

    Re: Function versus pointer to function, in context of std::function, huh?

    On 25 Jul., 14:50, Alf P. Steinbach wrote:
    > When I do this:
    >
    >    typedef function< void( Type const& ) > DestroyFunc;
    >
    > then Visual C++ 10.0 is happy.


    Right. The function template is declared/defined like this:

    template<class Signature>
    class function; // intentionally undefined

    template<class Ret, class...Params>
    class function<Ret(Params...)> {
    ...
    };

    So, in your case, Ret=void and Params...=Type const&

    > But when I do this:
    >
    >    typedef function< void(*)( Type const& ) > DestroyFunc;
    >
    > then it spews out a long sequence of silly error messages, like


    Yes. This partial specialization from above does not apply and the
    primary template is undefined. That's why you get the error. You
    passed a T* instead of a R(P...) type with T = void(Type const&).

    > What? Isn't that function type decaying to pointer to function type?


    There is no specialization for function pointer types. And types don't
    decay. Just expressions do. The template parameter is supposed to be a
    "signature" (return type and parameters).

    > And
    > if it isn't, shouldn't std::function be able to tackle pointer to
    > function type?


    Not as its template parameter, no. Why should it?

    Cheers!
    SG
    SG, Jul 26, 2011
    #3
  4. On 26.07.2011 10:33, SG wrote:
    > On 25 Jul., 14:50, Alf P. Steinbach wrote:
    >
    >> ..., shouldn't std::function be able to tackle pointer to
    >> function type?

    >
    > Not as its template parameter, no. Why should it?


    For usability.

    Lots of function types are defined by libraries.

    Usually, I dare say nearly always, as pointer to function.

    With current limitations, instead of

    function< WNDPROC >

    I probably have to write something like

    function< decltype( *(WNDPROC()) ) >

    or whatever the syntax is for decltype, but anyway, why should the
    programmer have to write that when the template could/should do it?


    Cheers, & thanks,

    - Alf
    Alf P. Steinbach, Jul 26, 2011
    #4
  5. Alf P. Steinbach

    Qi Guest

    On 2011-7-26 16:48, Alf P. Steinbach wrote:
    > I probably have to write something like
    >
    > function< decltype( *(WNDPROC()) ) >
    >
    > or whatever the syntax is for decltype, but anyway, why should the
    > programmer have to write that when the template could/should do it?


    Or you can write some wrapper template

    // not compiled code
    template <typename T>
    struct FunctionType
    {
    typedef boost::function<T> Result;
    };

    template <typename T>
    struct FunctionType <T *>
    {
    typedef boost::function<T> Result;
    };

    Or don't use specialization, remove pointer in first template.

    But why do you want to use boost::function?
    I won't use a function object wrapper that can't use member
    function directly. (bind? no...)


    --
    WQ
    Qi, Jul 26, 2011
    #5
  6. Alf P. Steinbach

    SG Guest

    Re: Function versus pointer to function, in context of std::function, huh?

    On 26 Jul., 10:48, Alf P. Steinbach wrote:
    > [...]
    > I probably have to write something like
    >
    >    function< decltype( *(WNDPROC()) ) >
    >
    > or whatever the syntax is for decltype,


    *(WNDPROC()) is not a name but an lvalue expression referring to a
    function. As such, decltype is forced to yield an lvalue-reference-to-
    function type which is also not viable as template parameter for
    std::function<>.

    > but anyway, why should the
    > programmer have to write that when the template could/should do it?


    I don't see the value in this. You'd end up with distinct but
    equivalent types with the exact same purpose. In your case:
    function<void(*)()> and function<void()>. I would prefer transforming
    the type before it's used as template parameter for function<>. But
    that's just me.

    SG
    SG, Jul 26, 2011
    #6
  7. On 26.07.2011 14:39, SG wrote:
    > On 26 Jul., 10:48, Alf P. Steinbach wrote:
    >> [...]
    >> I probably have to write something like
    >>
    >> function< decltype( *(WNDPROC()) )>
    >>
    >> or whatever the syntax is for decltype,

    >
    > *(WNDPROC()) is not a name but an lvalue expression referring to a
    > function. As such, decltype is forced to yield an lvalue-reference-to-
    > function type which is also not viable as template parameter for
    > std::function<>.


    That sounds rather impractical and at odds with the usual "reference
    can't be detected".

    I haven't checked but assume you're right.

    I also assume that good old `typeof` (from e.g. g++) was more practical.

    I'm just starting to use the C++0x stuff, it doesn't seem that
    well-designed.

    So, does one have to use some template stuff like
    PointeeType<WndProc>::T, where a reader of code must look elsewhere for
    definition, or can decltype be brought into service via some proper
    black magic incantantion?


    >> but anyway, why should the
    >> programmer have to write that when the template could/should do it?

    >
    > I don't see the value in this. You'd end up with distinct but
    > equivalent types with the exact same purpose. In your case:
    > function<void(*)()> and function<void()>.


    You mention that as if it were some kind of problem?

    What problem do you see with that?

    Since we're dealing with such equivalence in practice anyway, e.g. decay
    to pointer type everywhere a function type is used as formal argument
    type, I really don't see any problem.


    > I would prefer transforming
    > the type before it's used as template parameter for function<>. But
    > that's just me.


    No, it's probably not just you. There is a kind of fad of reversing the
    principle of least redundancy. Of writing as many ungrokkable technical
    details up front as possible, repeated each place instead of being
    centralized somewhere, in order to make the code look less clear; a sort
    of misguided and almost feminine attempt to *look* technical.


    Cheers,

    - Alf
    Alf P. Steinbach, Jul 26, 2011
    #7
  8. Alf P. Steinbach

    Noah Roberts Guest

    On 7/26/2011 3:08 AM, Qi wrote:
    > On 2011-7-26 16:48, Alf P. Steinbach wrote:
    > > I probably have to write something like
    > >
    > > function< decltype( *(WNDPROC()) ) >
    > >
    > > or whatever the syntax is for decltype, but anyway, why should the
    > > programmer have to write that when the template could/should do it?

    >
    > Or you can write some wrapper template
    >
    > // not compiled code
    > template <typename T>
    > struct FunctionType
    > {
    > typedef boost::function<T> Result;
    > };
    >
    > template <typename T>
    > struct FunctionType <T *>
    > {
    > typedef boost::function<T> Result;
    > };


    Or

    template < typename T >
    struct FunctionType<T*>
    : FunctionType<typename std::remove_const<T>::type>
    {};

    template < typename T >
    struct FunctionType<T&>
    : FunctionType<typename std::remove_const<T>::type>
    {};

    I believe this would remove any pointer or reference appendages, no
    matter how deep, and construct a function type out of whatever you pass in.
    Noah Roberts, Jul 26, 2011
    #8
  9. Alf P. Steinbach

    SG Guest

    Re: Function versus pointer to function, in context of std::function, huh?

    On 26 Jul., 17:49, Alf P. Steinbach wrote:
    > On 26.07.2011 14:39, SG wrote:
    > > *(WNDPROC()) is not a name but an lvalue expression referring to a
    > > function. As such, decltype is forced to yield an lvalue-reference-to-
    > > function type which is also not viable as template parameter for
    > > std::function<>.

    >
    > That sounds rather impractical and at odds with the usual "reference
    > can't be detected".


    It's more powerful than typeof.

    > I also assume that good old `typeof` (from e.g. g++) was more practical.


    I agree that in many cases the behaviour of the typeof extension is
    all you need. And in some cases it won't. (Think of how to implement
    result_of<>). I expect to see many decltype uses similar to this:

    template<class T, class U>
    auto operator*(vec3<T> const& v, U s) -> vec3<decltype(p[0]*s)>;

    where replacing decltype with typeof ought not to make a difference.
    And if you really need the typeof behaviour very often, you may use
    this shortcut:

    #include <type_traits>
    #define TYPEOF(xpr) typename std::decay<decltype(xpr)>::type

    Since C++2011 allows the typename keyword to appear in more contexts
    (including non-template ones) this macro should just work everywhere.

    > I'm just starting to use the C++0x stuff,
    > it doesn't seem that well-designed.


    There are some little warts here and there, but all in all I'm very
    happy with how things turned out.

    > So, does one have to use some template stuff like
    > PointeeType<WndProc>::T, where a reader of code must look elsewhere for
    > definition, or can decltype be brought into service via some proper
    > black magic incantantion?


    I don't think so.

    > >> but anyway, why should the
    > >> programmer have to write that when the template could/should do it?

    >
    > > I don't see the value in this. You'd end up with distinct but
    > > equivalent types with the exact same purpose. In your case:
    > > function<void(*)()>  and function<void()>.

    >
    > You mention that as if it were some kind of problem?
    > What problem do you see with that?


    It's the principle of the matter. You end up with two different types
    that could have been one. It complicates things. Will a
    function<void(*)()> be convertible to a function<void()> and/or the
    other way around? If not why not? Also, the types are not reference-
    compatible.

    > Since we're dealing with such equivalence in practice anyway, e.g. decay
    > to pointer type everywhere a function type is used as formal argument
    > type, I really don't see any problem.


    I really don't see any advantage. And I really don't like the let's-
    just-use-two-distinct-types-for-the-same-thing strategy. :p

    If you hate his so much you could write a proposal to give
    std::function some other implementation-defined name (i.e.
    std::_function_) and to create a type-transforming alias that emulates
    this decay for types:

    template<class T> struct aftt_ { typedef T type; };
    template<class T> struct aftt_<T*> : aftt_<T> {};
    template<class T> struct aftt_<T&> : aftt_<T> {};
    template<class T> using function = _function_<typename
    aftt_<T>::type>;

    With this, function<void()> and function<void(*)()> would be
    synonymous with _function_<void()> and all these names would refer to
    exactly one type (and we both can live in peace). ;-)

    > [...opinion...]


    That's yours. I have mine.

    Cheers!
    SG
    SG, Jul 26, 2011
    #9
  10. Alf P. Steinbach

    Qi Guest

    On 2011-7-27 2:21, SG wrote:

    >>> I don't see the value in this. You'd end up with distinct but
    >>> equivalent types with the exact same purpose. In your case:
    >>> function<void(*)()> and function<void()>.


    The problem is, boost::function already supports two syntax.

    Preferred syntax
    boost::function<float (int x, int y)> f;

    Portable syntax
    boost::function2<float, int, int> f;

    If it only supports first syntax, we can say it's how
    it works and won't complain that it doesn't supports
    function pointer syntax.

    But since it already supports the two syntax, I can't see
    why it doesn't supports the function pointer syntax, which
    is more common accepted than function type, IMHO.

    Of course it's the library provider's choice, so I won't
    complain more (and I don't use boost::function). :)


    --
    WQ
    Qi, Jul 27, 2011
    #10
  11. On 26.07.2011 20:21, SG wrote:
    > On 26 Jul., 17:49, Alf P. Steinbach wrote:
    >

    [about ability to write std::function<FunctionPtrType> ]
    >>>> but anyway, why should the
    >>>> programmer have to write that when the template could/should do it?

    >>
    >>> I don't see the value in this. You'd end up with distinct but
    >>> equivalent types with the exact same purpose. In your case:
    >>> function<void(*)()> and function<void()>.

    >>
    >> You mention that as if it were some kind of problem?
    >> What problem do you see with that?

    >
    > It's the principle of the matter. You end up with two different types
    > that could have been one. It complicates things.


    The person with nick "Qi" notes else-sub-thread that boost::function
    *already* has two different C++ types for each logical one, in order to
    support TMP-challenged compilers.

    And I noted that in dealing with functions in non-template contexts, we
    already have two different C++ types for each logical one, e.g. void()
    and void(*)().

    And this is not problematic, and it's not complicated, to a C++
    programmer. :)


    > Will a
    > function<void(*)()> be convertible to a function<void()> and/or the
    > other way around?


    Of course, we're talking CALLABLE ENTITIES here.


    > If not why not? Also, the types are not reference-
    > compatible.


    The problem of reference compatibility between int(double) and
    int(*)(double) has never been a critical one.

    It is simply not an issue of in-practice programming.

    However, the ability to use the newfangled stuff (like std::function)
    directly with the old stuff (like library typedefs of functions) IS a
    practical issue. Programmers should not have to work around artificial
    limitations of the standard library. That's absurd, but, we're there!


    >> Since we're dealing with such equivalence in practice anyway, e.g. decay
    >> to pointer type everywhere a function type is used as formal argument
    >> type, I really don't see any problem.

    >
    > I really don't see any advantage. And I really don't like the let's-
    > just-use-two-distinct-types-for-the-same-thing strategy. :p
    >
    > If you hate his so much you could write a proposal to give
    > std::function some other implementation-defined name (i.e.
    > std::_function_) and to create a type-transforming alias that emulates
    > this decay for types:
    >
    > template<class T> struct aftt_ { typedef T type; };
    > template<class T> struct aftt_<T*> : aftt_<T> {};
    > template<class T> struct aftt_<T&> : aftt_<T> {};
    > template<class T> using function = _function_<typename
    > aftt_<T>::type>;


    I really appreciate your attempt to help.

    The above attempted solution is, however, both wrong and currently
    impractical.

    It's wrong, because it would let you use e.g. a pointer to pointer to
    function type as template argument to std::function.

    A pointer to pointer to function is something else entirely. There is no
    convention going all the way back to 1974, or whatever year it was, of
    using that to represent a function type, and no library you're using
    will typedef such a type as a function type. So, accepting such types
    would be supporting a never naturally occurring use case, and would
    needlessly allow bugs to go unnoticed by turning off the type checking
    for a number of forms (instead one might use std::remove_pointer).

    Regarding that it's currently impractical, that's because Visual C++
    10.0 does not yet support the template "using". Alas. I really like the
    nifty type notation that it allows and that Johannes has been promoting
    everywhere, defining "template< class T > using Type = T" he he.


    Cheers,

    - Alf
    Alf P. Steinbach, Jul 27, 2011
    #11
    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. Replies:
    30
    Views:
    1,187
  2. Disc Magnet
    Replies:
    1
    Views:
    623
    Ian Collins
    May 6, 2010
  3. Paul Butcher
    Replies:
    12
    Views:
    701
    Gary Wright
    Nov 28, 2007
  4. Bo Lindbergh

    List context versus list context

    Bo Lindbergh, Jun 21, 2006, in forum: Perl Misc
    Replies:
    12
    Views:
    221
    Charles DeRykus
    Jun 28, 2006
  5. Jeremy Murphy
    Replies:
    5
    Views:
    472
    Jeremy Murphy
    Dec 13, 2012
Loading...

Share This Page