type of a lambda expression

  • Follow


Hi,

how can I declare a function which takes a lambda-expression.
Naively, I tried


// compile with gcc-4.5  -std=c++0x

#include <iostream>
using std::cout;  using std::cerr;  using std::cin;  using std::endl;

void calc(double x, double CVT(double)) {
  cout << "\nresult= " << CVT(x) << endl;
}

int main() {
  double F;
  cerr << "F= "; cin >> F;

  calc(3.14,[&](double z) -> double { return F*z; } );
}

But it fails, since it cannot convert the lambda-expression to
a double (*)(double).

What is the correct declaration of the function 'calc'.

Many thanks for a hint and pointers to tutorials on that subject.
Sorry, but I couldn't extract that information out of the N2550 document.

Helmut.

-- 
Helmut Jarausch

Lehrstuhl fuer Numerische Mathematik
RWTH - Aachen University
D 52056 Aachen, Germany

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply jarausch2 (106) 4/14/2010 12:19:03 PM

On 14 Apr., 20:19, Helmut Jarausch <jarau...@igpm.rwth-aachen.de>
wrote:
> how can I declare a function which takes a lambda-expression.
> Naively, I tried
>
> // compile with gcc-4.5  -std=c++0x
>
> #include <iostream>
> using std::cout;  using std::cerr;  using std::cin;  using std::endl;
>
> void calc(double x, double CVT(double)) {
>   cout << "\nresult= " << CVT(x) << endl;
>
> }
>
> int main() {
>   double F;
>   cerr << "F= "; cin >> F;
>
>   calc(3.14,[&](double z) -> double { return F*z; } );
> }
>
> But it fails, since it cannot convert the lambda-expression to
> a double (*)(double).
>
> What is the correct declaration of the function 'calc'.
>
> Many thanks for a hint and pointers to tutorials on that subject.
> Sorry, but I couldn't extract that information out of the N2550 document.

The most recent working draft is N3090 (which has
the same content as the recently passed FCD).

Regarding your particular use-case there does not
exist a non-template solution. The current wording
says that any lambda closure with *no* lambda-capture
has a publicly available conversion function to
pointer to function that has the same return type
and parameter types as the lambda closure. In your
example you use a non-empty capture (and you need
that), so you would need to provide a template
function that uses the function call operator
of the closure.

HTH & Greetings from Bremen,

Daniel Kr�gler


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply ISO 4/14/2010 4:58:10 PM


On 14/04/10 21:19, Helmut Jarausch wrote:
> Hi,
>
> how can I declare a function which takes a lambda-expression.
> Naively, I tried
>
> [...]
>
> What is the correct declaration of the function 'calc'.
>

Every lambda expression has its own type which is known only by the
compiler. To store the lambda expression in a local variable you can use
'auto' to infer its type, but to pass it to another function you can:

a) Make that function a template so the compiler can instantiate it with
the exact inferred type of the lambda.

This is:

template <typename Func>
void calc (double x, Func cvt);

b) Use std::function for type erasure, this is:

void calc (double x, std::function <double (double)> cvt);

The (a) case is more efficient because the function is instantiated for
the exact type of the lambda and potentially use the stack to store the
closure while (b) would potentially store the closure in the heap and
add a extra level of indirection. On the other hand, (a) has all the
limitations of templated functions: cannot be overriden in sub-classes,
their implementation have to be exposed in header files, etc, while
option (b) does not.

JP

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Juan 4/14/2010 4:59:07 PM

On 14 avr, 19:19, Helmut Jarausch <jarau...@igpm.rwth-aachen.de>
wrote:
> Hi,
>
> how can I declare a function which takes a lambda-expression.
> Naively, I tried
>
> // compile with gcc-4.5  -std=c++0x
>
> #include <iostream>
> using std::cout;  using std::cerr;  using std::cin;  using std::endl;
>
> void calc(double x, double CVT(double)) {
>   cout << "\nresult= " << CVT(x) << endl;
>
> }
> [...]
> What is the correct declaration of the function 'calc'.

template<typename F>
void calc(double x, F&& CVT) {
    cout << "\nresult= " << CVT(x) << endl;
}

Alternatively you can use std::function or std::nested_function.


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Mathias 4/14/2010 4:59:25 PM

On Apr 14, 2:19 pm, Helmut Jarausch <jarau...@igpm.rwth-aachen.de>
wrote:
> Hi,
>
> how can I declare a function which takes a lambda-expression.
> Naively, I tried

> void calc(double x, double CVT(double)) {
>   cout << "\nresult= " << CVT(x) << endl;
>
> }

> int main() {
>   double F;
>   cerr << "F= "; cin >> F;
>
>   calc(3.14,[&](double z) -> double { return F*z; } );
>
> }
>
> But it fails, since it cannot convert the lambda-expression to
> a double (*)(double).
>
> What is the correct declaration of the function 'calc'.

Making calc work only for lambdas might be difficult, they have no
standard-defined type. But, i don't think you want to make it so calc
will take ONLY lambdas anyway, since the usability of it will be
limited, especially to people NOT using -std=c++0x when they compile.

template< typename F >
void calc( double x, F f )
{
     cout << "\nresult= " << f(x) << endl;
}

Here, the argument f can be a function pointer, a function object, or
a lambda. As long as type F fulfills to requirement of having
operator()(double), this will work. You can also use
std::tr1::function which has a typedef for result_type.


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Hakusa 4/14/2010 5:00:35 PM

On 14 Apr., 20:19, Helmut Jarausch wrote:
>
> how can I declare a function which takes a lambda-expression.
> Naively, I tried
>
> // compile with gcc-4.5  -std=c++0x
>
> #include <iostream>
> using std::cout;  using std::cerr;  using std::cin;  using std::endl;
>
> void calc(double x, double CVT(double)) {
>   cout << "\nresult= " << CVT(x) << endl;
> }
>
> int main() {
>   double F;
>   cerr << "F= "; cin >> F;
>
>   calc(3.14,[&](double z) -> double { return F*z; } );
> }
>
> But it fails, since it cannot convert the lambda-expression to
> a double (*)(double).

The C++ standard will allow conversions to function pointers but not
in cases like these. Remember that the lambda syntax does two things:
It defines a new nameless type and creates an object of this type. In
its operator() member function you access something called F. You
could think of F as a reference member of that class. With this im
mind it should be obvious why there cannot be a conversion to a
function pointer. Your pointer CVT is a pointer to a free function
which doesn't have any kind of data or reference to data (like F)
attached to it.

> What is the correct declaration of the function 'calc'.

You have basically two options. 1.:

   template<class Fun>
   void calc(double x, Fun fun)
   {
     cout << "\nresult= " << fun(x) << endl;
   }

2.:

   #include <function>

   void calc(double x, std::function<double(double)> fun)
   {
     cout << "\nresult= " << fun(x) << endl;
   }


Cheers,
SG


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply SG 4/14/2010 5:34:05 PM

> how can I declare a function which takes a lambda-expression.
> Naively, I tried

I think you have two options:

1) Use template argument T
2) Use std::function argument


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Thiago 4/14/2010 5:37:07 PM

Hi,

::But it fails, since it cannot convert the lambda-expression to
::a double (*)(double).

I suspect that you received the following warning (or similar):
lambdaold.cpp:31:53: error: cannot convert ‘main()::<lambda(double)>’ to ‘double (*)(double)’ for argument ‘2’ to ‘void calc(double, double (*)(double))’


::What is the correct declaration of the function 'calc'.

I think the warning is related to the fact, that the lambda function uses variables local to the function main (). The following compiles here (gcc version 4.5.0 20100404 (experimental) [trunk revision 157958] (Debian 4.5-20100404-1)) without a warning:

#include <iostream>
using std::cout;  using std::cerr;  using std::cin;  using std::endl;

void calc(double x, double (CVT)(double)) {
   cout << "\nresult= " << CVT(x) << endl;
}

int a = 10;
int main() {
   calc (2.71, [&](double z) -> double { return a*z; });
}

Whereas it failes with the upper error message using

int main() {
   int a = 10;
   calc (2.71, [&](double z) -> double { return a*z; });
}


I don't know if the error your source reproduces should be considered as a bug, what does the c++0x say about lambda expressions which use local variables?


Greetings, Magnus


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Magnus 4/14/2010 5:41:38 PM

On 15 Apr., 01:41, Magnus M�ller <mamue...@informatik.hu-berlin.de>
wrote:
> Hi,
>
> ::But it fails, since it cannot convert the lambda-expression to
> ::a double (*)(double).
>
> I suspect that you received the following warning (or similar):
> lambdaold.cpp:31:53: error: cannot convert �main()::<lambda(double)>� to �double (*)(double)� for argument �2� to �void calc(double, double (*)(double))�
>

Well, this looks like a funny description of a "warning" ;-)

> ::What is the correct declaration of the function 'calc'.
>
> I think the warning is related to the fact, that the lambda function uses variables local to the function main (). The following compiles here (gcc version 4.5.0 20100404 (experimental) [trunk revision 157958] (Debian 4.5-20100404-1)) without a warning:
>
> #include <iostream>
> using std::cout;  using std::cerr;  using std::cin;  using std::endl;
>
> void calc(double x, double (CVT)(double)) {
>    cout << "\nresult= " << CVT(x) << endl;
>
> }
>
> int a = 10;
> int main() {
>    calc (2.71, [&](double z) -> double { return a*z; });
> }

If this is well-formed, the compiler provides an
extension. Per current working draft there should
be no conversion function for lambda closures with
a lambda-capture. In your example exists a lambda-
capture, even though there is no captured variable.
But the term lambda-capture is defined per grammar
and the code uses this grammar, therefore this
code should be ill-formed.

> Whereas it failes with the upper error message using
>
> int main() {
>    int a = 10;
>    calc (2.71, [&](double z) -> double { return a*z; });
>
> }
>
> I don't know if the error your source reproduces should be considered as a bug, what does the c++0x say about lambda expressions which use local variables?
>

The current working draft refers to the existence
or absence of lambda-capture. This is the "[&]"
in above example and can take different forms.
If no lambda-capture exists, there is the guarantee
that no local variables are "captured". This is
necessary to allow for a conversion function to
a pointer to a function, because this pointer
must point to some function that can be defined
without state.

HTH & Greetings from Bremen,

Daniel Kr�gler



-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply ISO 4/15/2010 12:53:17 AM

8 Replies
215 Views

(page loaded in 0.134 seconds)

Similiar Articles:












7/13/2012 10:37:50 AM


Reply: