Why does "template<typename T> ... function<T(int)>" not match "int(&)(int)" implicitly?

Discussion in 'C++' started by Steve Hicks, Sep 27, 2009.

  1. Steve Hicks

    Steve Hicks Guest

    Hi,

    I'm using g++-4.3.3 and trying to compile the following minimal code

    #include <tr1/functional>
    using std::tr1::function;
    int foo(int x) { return x+1; }
    template <typename T> T bar(function<T(int)> f,int a) { return f(a); }
    int main() { return bar(foo,1); }

    and I get the error "no matching function for call to ‘bar(int (&)
    (int), int)". It works if I change bar to take a function<int(int)>.
    It also works if I add an explicit cast, as in bar((function<int(int)>)
    foo,1). And I know the constructor is implicit, since I can say
    "function<int(int)> foo_f = foo; bar(foo_f,1);" and it works just
    fine. My code also fails when using a function object (with a member
    int operator()(int)).

    But I'm trying to make a function similar to bind, where you can pass
    any sort of function reference/pointer/object/etc without any explicit
    casts, and it "just works" (in fact, I'd rather take a function<T(A)>
    with both types templated, but one thing at a time...)

    I looked at gcc's tr1_impl/functional header and see that function
    objects and bind take all sorts of scary-looking variadic templates,
    and the entire functor input is a single template _Functor, rather
    than an explicit function<T(A)>. But since function<> does have these
    implicit constructors, is there any way to help out the compiler in
    figuring out what's so obvious to a human? It seems like matching the
    argument types is much more straightforward if I can just specify the
    same A in both arguments bar(function<T(A)>,A)... I wouldn't even know
    how to start making sense of it when the functor and the argument
    types are separate templates. How can I go about doing that, if it's
    actually necessary?

    Thanks,
    Steve
     
    Steve Hicks, Sep 27, 2009
    #1
    1. Advertising

  2. Re: Why does "template<typename T> ... function<T(int)>" not match"int (&)(int)" implicitly?

    Steve Hicks wrote:
    > Hi,
    >
    > I'm using g++-4.3.3 and trying to compile the following minimal code
    >
    > #include <tr1/functional>
    > using std::tr1::function;
    > int foo(int x) { return x+1; }
    > template <typename T> T bar(function<T(int)> f,int a) { return f(a); }
    > int main() { return bar(foo,1); }
    >


    This fixes it:
    int main() { return bar< int >(foo,1); }

    In your example, type T can not be deduced.

    <...>
     
    Vladimir Jovic, Sep 28, 2009
    #2
    1. Advertising

  3. Steve Hicks

    SG Guest

    Re: Why does "template<typename T> ... function<T(int)>" not match"int (&)(int)" implicitly?

    Steve Hicks wrote:
    >
    > #include <tr1/functional>
    > using std::tr1::function;
    > int foo(int x) { return x+1; }
    > template <typename T> T bar(function<T(int)> f,int a) { return f(a); }
    > int main() { return bar(foo,1); }
    >
    > and I get the error "no matching function for call to ‘bar(int (&)
    > (int), int)".  It works if I change bar to take a function<int(int)>.


    Right. The difference is that T doesn't have to be deduced anymore.

    > It also works if I add an explicit cast, as in bar((function<int(int)>)
    > foo,1).


    Right. In this case (the type matches exactly) the compiler is able to
    deduce T. You can also write bar<int>(foo,1) -- specifying T so no
    deduction has to be performed. You could even write bar<void>(foo,1)
    or bar<double>(foo,1) as far as I can tell. So the number of possible
    type parameters with successfull template instantiations is even
    greater than one. What's the "right" one?

    > And I know the constructor is implicit, since I can say
    > "function<int(int)> foo_f  = foo; bar(foo_f,1);" and it works just
    > fine.  My code also fails when using a function object (with a member
    > int operator()(int)).


    Right. Because the types don't match. Your function object is not a
    std::function and therefore type deduction of T won't work. Type
    deduction only considers array-to-pointer, function-to-pointer, cv
    qualification, and derived-to-base conversions. Nothing else. No other
    implicit conversions. This is a good thing, actually. ;-)

    > But I'm trying to make a function similar to bind, where you can pass
    > any sort of function reference/pointer/object/etc without any explicit
    > casts, and it "just works" (in fact, I'd rather take a function<T(A)>
    > with both types templated, but one thing at a time...)


    You could try to use overloading and SFINAE to "detect the correct T"
    for non-function<> objects:

    template <typename T>
    T bar(function<T(int)> f,int a)
    {
    ... your code ...
    }

    template <typename Func>
    inline typename result_of<Func(int)>::type
    bar(Func const& fun, int a)
    {
    typedef typename result_of<Func(int)>::type ret_t;
    return bar<ret_t>(fun,a); // relay
    }

    The first function template accepts function<T(int)> objects directly
    for some T (if T can be deduced or is explicitly given and an implicit
    conversion exists. The second function takes any functor, tries to
    detect the return type when given an int parameter and relays to the
    first function. Wrapping the functor in a function<> object is done
    implicitly since the type parameter is specified and doesn't need to
    be deduced. -- I havn't tested the code above, though.

    > I looked at gcc's tr1_impl/functional header and see that function
    > objects and bind take all sorts of scary-looking variadic templates,
    > and the entire functor input is a single template _Functor, rather
    > than an explicit function<T(A)>.


    Yeah, why not? If you don't want the code bloat and don't mind the
    virtual function call overhead you can always try to wrap the functor
    manually in a function<> object like I did above.

    > But since function<> does have these
    > implicit constructors, is there any way to help out the compiler in
    > figuring out what's so obvious to a human?


    See above.

    Cheers,
    SG
     
    SG, Sep 28, 2009
    #3
    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. Patrick Olurotimi Ige

    Cannot implicitly convert type 'object' to 'bool' Error

    Patrick Olurotimi Ige, Jan 25, 2005, in forum: ASP .Net
    Replies:
    2
    Views:
    12,214
    Patrick Olurotimi Ige
    Jan 25, 2005
  2. Andy Sutorius
    Replies:
    9
    Views:
    20,565
    Kevin Spencer
    Feb 22, 2005
  3. Patrick Olurotimi Ige
    Replies:
    3
    Views:
    8,737
    Patrick Olurotimi Ige
    May 4, 2005
  4. Mr. SweatyFinger

    why why why why why

    Mr. SweatyFinger, Nov 28, 2006, in forum: ASP .Net
    Replies:
    4
    Views:
    910
    Mark Rae
    Dec 21, 2006
  5. Mr. SweatyFinger
    Replies:
    2
    Views:
    1,999
    Smokey Grindel
    Dec 2, 2006
Loading...

Share This Page