5

The problem I'm facing is straightforward. Given the following code:

template <typename ReturnType, typename... Args>
auto CallIt( ReturnType( *method )( Args... ) )
{
    return method;
}

auto test = CallIt( [] ( int a, int b )
{
    return a > b;
} );

The error that I get (using VS13 with the November 2013 CTP compiler) is:

Could not deduce template argument for ReturnType (__cdecl *)(Args...) from main::<lambda_e795bf5a030334e5fc8f3c26dbe00e0e>

I understand that a lambda is not a function pointer, but a lambda that does not capture can be assigned to a function pointer of a matching signature. If you explicitly specify the template arguments, this works. I would love to see a way where this can work without having to explicitly specify the template arguments. Thank you in advance for your help.

As noted in the comments for the answer provided by Marco A., there may be a solution to this using the unary + operator on the lambda class, effectively casting it to a function pointer. However, in the requested IDE/compiler combination I receive the following warning-turned-error:

more than one conversion function from "lambda []bool (int a, int b)->bool" to a built-in type applies:

function "lambda []bool (int a, int b)->bool::operator bool (*)(int a, int b)() const"

function "lambda []bool (int a, int b)->bool::operator bool (*)(int a, int b)() const"

function "lambda []bool (int a, int b)->bool::operator bool (*)(int a, int b)() const"

function "lambda []bool (int a, int b)->bool::operator bool (*)(int a, int b)() const"

This intellisense error sheds light on the compile error generated specifying:

error C2593: 'operator +' is ambiguous

TylerH
  • 20,799
  • 66
  • 75
  • 101
Will Custode
  • 4,576
  • 3
  • 26
  • 51
  • 1
    Template functions get no type deduction, and converting from Lambda to a function pointer probably involves some implied conversion. See [this](http://stackoverflow.com/questions/25020680/automatic-conversion-of-function-arguments-between-related-template-classes/25020852#comment38909755_25020852) previous question for ways around this problem. – Suedocode Jul 30 '14 at 14:02

1 Answers1

4

1) Add a proper trailing return type

2) If you wish to pass a function pointer, have the lambda conform to that

template <typename ReturnType, typename... Args>
auto CallIt( ReturnType( *method )( Args... ) ) -> ReturnType(*)(Args...)
{
    return method;
}

auto test = CallIt( +[] ( int a, int b )
{
    return a > b;
} );

Live Example


Edit: it seems there's something wrong with MSVC2013. As a workaround you might try if the following works for the time being:

#include <iostream>
#include <functional>
using namespace std;

template <typename ReturnType, typename... Args>
auto CallIt( std::function<ReturnType( Args... )> method ) -> std::function<ReturnType( Args... )>
{
    return method;
}

int main() {

    std::function<bool(int,int)> lambda = [] ( int a, int b ) { return a > b; };

    auto test = CallIt( lambda );
    cout << test(4,1);


    return 0;
}

Live Example

Community
  • 1
  • 1
Marco A.
  • 43,032
  • 26
  • 132
  • 246
  • 1
    Can you elaborate on why the prefix `+` operator is needed here ? – Chnossos Jul 30 '14 at 14:06
  • @Chnossos It's explained in the link posted: it permits the conversion lambda -> function pointer. – JBL Jul 30 '14 at 14:08
  • There was no link when I asked. Thank you for providing it. – Chnossos Jul 30 '14 at 14:09
  • @Chnossos Keep in mind that the type of a lambda expression is unspecified, you're asking here to receive a pointer to a function with a specific signature with no wrappers involved – Marco A. Jul 30 '14 at 14:09
  • 1
    This is the first I've ever heard of the `+` prefix on lambdas, and I'm having trouble with this using the IDE/compiler specified. The error says `operator+ is ambiguous`. – Will Custode Jul 30 '14 at 14:20
  • 2
    @WilliamCustode: well, it should not be... it works with gcc and clang, so I guess this is another VS quirk. – Matthieu M. Jul 30 '14 at 14:29
  • @WilliamCustode it should be supported in VS2013 (not sure about the revision): http://msdn.microsoft.com/en-us/library/hh567368.aspx#lambdas – Marco A. Jul 30 '14 at 14:29
  • @MarcoA. I don't see where it specifies this functionality is supported. – Will Custode Jul 30 '14 at 14:37
  • @WilliamCustode I linked the passage which cites expr.prim.lambda from the standard. If this proves to be impossible you might try to wrap as I did above, take a look at the edit. I have no idea if that works on MSVC2013 but it should be correct. – Marco A. Jul 30 '14 at 14:51
  • It's a little late, but this example is part of a solution I'm trying to implement to circumvent using `std::function` – Will Custode Jul 30 '14 at 15:10