Bug 46719 - [C++0x] Cannot call variadic function template
Summary: [C++0x] Cannot call variadic function template
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.6.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-11-30 03:04 UTC by Eric Lawless
Modified: 2010-12-01 03:00 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Eric Lawless 2010-11-30 03:04:45 UTC
The following function template compiles without issue:

    template <typename Return, typename FirstType, typename... ArgTypes>
    function<Return(ArgTypes...)>
    curry(function<Return(FirstType,ArgTypes...)> func, FirstType arg)
    {
        return [func, arg](ArgTypes... args) -> Return {
            return func(arg, args...);
        };
    }

But as soon as I try to call it, like so:

    int main()
    {
        cout << curry([](int x) -> double {
            return static_cast<double>(x);
        }, 10)();
        return 0;
    }

It throws the following error:

    error: no matching function for call to ‘curry(main()::<lambda(int)>, int)’

The version of G++ used was:

    g++ (GCC) 4.6.0 20101113 (experimental)
Comment 1 Jonathan Wakely 2010-11-30 10:36:42 UTC
Reduced to get rid of library dependencies:

template <typename Return, typename... ArgTypes>
    struct function
    {
        template<typename Functor> function(Functor) { }
    };

template <typename Return, typename FirstType, typename... ArgTypes>
    int
    curry(function<Return(FirstType,ArgTypes...)> func, FirstType)
    {
        return 0;
    }


int main()
{
    return curry( [](int x) -> double { return static_cast<double>(x); }, 10 );
}
Comment 2 Paolo Carlini 2010-11-30 10:57:23 UTC
Thanks Jon, let's add Jason in CC.
Comment 3 Kohei Takahashi 2010-11-30 19:45:34 UTC
The error is not bug because C++0x Lambda is not a std::function (or boost::function and so on...).
C++0x Lambda is a unique, unnamed non-union class type. (written in n3126, 5.1.2.3. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3126.pdf)

Therefore compiler is unable to deduce template parameters that are Return, FirstType and ArgTypes.

If you want to call function with implicitly template arguments deduction, you should use variable, cast or constructor call like following code.

example:
  int main()
  {
    // using variable
    function< double( int ) > f = []( int x ) { return static_cast< double >( x ); };
    curry( f, 10 );

    // or casting
    curry( static_cast< function< double( int ) > >( []( int x ) { return static_cast< double >( x ); } ), 10 );

    // or calling constructor
    curry( function< double( int ) >( []( int x ) { return static_cast< double >( x ); } ), 10 );
  }
Comment 4 Jonathan Wakely 2010-11-30 20:04:00 UTC
(In reply to comment #3)
> 
> Therefore compiler is unable to deduce template parameters that are Return,
> FirstType and ArgTypes.

Right, the lambda can be converted to double(*)(int) but that doesn't help. 

There is no valid conversion sequence that allows the compiler to deduce the template arguments.

Here's a version without a lambda:

template <typename Return, typename... ArgTypes>
    struct function
    {
        template<typename Functor> function(Functor) { }
    };

template <typename Return, typename FirstType, typename... ArgTypes>
    int
    curry(function<Return(FirstType,ArgTypes...)> func, FirstType)
    {
        return 0;
    }

double f(int x) { return static_cast<double>(x); }

int main()
{
    return curry( f, 10 );
}
Comment 5 Jonathan Wakely 2010-11-30 22:14:57 UTC
And here's an even simpler version without variadic templates or any other C++0x features:

template <typename R>
    struct function
    {
        template<typename F> function(F) { }
    };

template <typename R>
    int
    curry(function<R> func)
    {
        return 0;
    }

double f(int x) { return x; }

int main()
{
    return curry( f );
}


G++ is correct to reject this, there's no way to deduce R
Comment 6 Eric Lawless 2010-11-30 22:46:46 UTC
I think I did a bad job describing the issue, and I think that it's still a problem. I'd like to clarify it if I can. The following code works:

    template <typename Return, typename... Args> 
    int curry(function<Return(double)> func) // NOTE: double
    { 
        return 0; 
    } 

    int f(double x) 
    { 
        return 0; 
    } 

    int main() 
    { 
        curry<int, double>(f); 
    }

While this does not:

    template <typename Return, typename... Args> 
    int curry(function<Return(Args...)> func) // NOTE: Args...
    { 
        return 0; 
    } 

    int f(double x) 
    { 
        return 0; 
    } 

    int main() 
    { 
        curry<int, double>(f); 
    }

Even though the template parameter pack Args expands to double, GCC is unable to match f to the type function<int(double)> if I use Args..., where it was able to with the first example where I used double explicitly.

This is the error I receive:

    error: no matching function for call to ‘curry(int (&)(double))’

Thanks for your time.
Comment 7 Kohei Takahashi 2010-12-01 00:30:45 UTC
(In reply to comment #6)
> Even though the template parameter pack Args expands to double, GCC is unable
> to match f to the type function<int(double)> if I use Args..., where it was
> able to with the first example where I used double explicitly.

It seems different issue. At least initially report is not a bug.

You should write new bug report, correct this report or find similar bug reports.

Most simple issue code is following:

template < typename... >
struct S
{
    S( int );
};

template < typename... T >
void f( S< T... > );

void g( void )
{
    f< int >( 0 );
}
Comment 8 Jonathan Wakely 2010-12-01 01:51:06 UTC
(In reply to comment #6)
> I think I did a bad job describing the issue, and I think that it's still a
> problem. I'd like to clarify it if I can. The following code works:
> 
>     template <typename Return, typename... Args> 
>     int curry(function<Return(double)> func) // NOTE: double

Here, Args can never be deduced, so must be given explicitly.

>     { 
>         return 0; 
>     } 
> 
>     int f(double x) 
>     { 
>         return 0; 
>     } 
> 
>     int main() 
>     { 
>         curry<int, double>(f); 

Args... must be {double}
It is not possible to call curry() without giving all template args, so the compiler knows that the only viable specialisation is where Args...=double


>     }
> 
> While this does not:
> 
>     template <typename Return, typename... Args> 
>     int curry(function<Return(Args...)> func) // NOTE: Args...

Here Args... appears in a parameter and can be deduced.

>     { 
>         return 0; 
>     } 
> 
>     int f(double x) 
>     { 
>         return 0; 
>     } 
> 
>     int main() 
>     { 
>         curry<int, double>(f); 
>     }
> 
> Even though the template parameter pack Args expands to double, GCC is unable
> to match f to the type function<int(double)> if I use Args..., where it was

How does it know the template parameter pack expands to double? Maybe it expands to {double,T} and you want T to be deduced. Or maybe {double,T,U}

If you passed a function<int(double)> it could deduce Args, but passing f requires a user-defined conversion to an unknown type, so deduction cannot succeed.
Comment 9 Eric Lawless 2010-12-01 02:59:43 UTC
Jonathan, you're absolutely right. After some patient explanation by Johannes Schaub (litb) and Eelis van der Weegen (eelis) on IRC (FreeNode/##C++), I realize that GCC's behaviour here is standards-compliant. (Johannes directed me to 14.8.1/9 and 14.8.1/6 and 14.8.2.1/4 of n3126).
Comment 10 Eric Lawless 2010-12-01 03:00:17 UTC
Standards-compliant behaviour.