Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

C++11 lambdas and normal function pointers

82 views
Skip to first unread message

Jimmy H.

unread,
Mar 2, 2012, 4:00:42 PM3/2/12
to
In my compiler (gcc 4.6), the following compiles:

#include <cstdio>

typedef int (*callback)();

int main() {
int foo = 0;
callback c = [] () { return 3; };
for (int i = 0; i < 10; i++) {
printf("%i\n", c());
}
return 0;
}

But the following does not compile:

#include <cstdio>

typedef int (*callback)();

int main() {
int foo = 0;
callback c = [&] () { return foo++; };
for (int i = 0; i < 10; i++) {
printf("%i\n", c());
}
return 0;
}

Three questions:
* Is this first program's successful compilation in line with the C+
+11 standard, or is it a GCC extension?
* Is the rule then that lambdas without contexts are automatically
convertible to C-style function pointers, and that lambdas with
contexts are not?

And most interestingly:
* I know that GCC is capable of using trampolining (which works only
when writable pages can also be executable) to implement things
similar to the second, non-compiling program. Would gcc still be
standards-compliant if it allowed the second program, or does the
standard expressly forbid it? Or am I misunderstanding how standards
work?

- Jimmy


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

Daniel Krügler

unread,
Mar 3, 2012, 4:06:28 AM3/3/12
to
Am 02.03.2012 22:00, schrieb Jimmy H.:
> In my compiler (gcc 4.6), the following compiles:
>
> #include<cstdio>
>
> typedef int (*callback)();
>
> int main() {
> int foo = 0;
> callback c = [] () { return 3; };
> for (int i = 0; i< 10; i++) {
> printf("%i\n", c());
> }
> return 0;
> }
>
> But the following does not compile:
>
> #include<cstdio>
>
> typedef int (*callback)();
>
> int main() {
> int foo = 0;
> callback c = [&] () { return foo++; };
> for (int i = 0; i< 10; i++) {
> printf("%i\n", c());
> }
> return 0;
> }
>
> Three questions:
> * Is this first program's successful compilation in line with the C+
> +11 standard, or is it a GCC extension?

It is part of the standard. The standard requires that a lambda-closure
with *no* captured variables shall provide a non-explicit conversion
function to a function pointer that has the same signature as the
function call operator overload of the closure class.

> * Is the rule then that lambdas without contexts are automatically
> convertible to C-style function pointers, and that lambdas with
> contexts are not?

Exactly.

> And most interestingly:
> * I know that GCC is capable of using trampolining (which works only
> when writable pages can also be executable) to implement things
> similar to the second, non-compiling program. Would gcc still be
> standards-compliant if it allowed the second program, or does the
> standard expressly forbid it? Or am I misunderstanding how standards
> work?

I tend to argue that the compiler would still be conforming, at least if
we look at your example. The reason is that you could not create a
well-formed program without that conversion. The situation becomes a bit
more tricky when we involve this conversion with constrained templates.
Given C++11 capabilities, a conforming program could observe this
difference. Consider:

#include <type_traits>
#include <cassert>

template<class T, class P, class = typename std::enable_if<
std::is_convertible<T, P>::value
>::type>
std::true_type f(int){ return std::true_type(); }

template<class, class>
std::false_type f(...){ return std::false_type(); }

typedef int (*callback)();

int main() {
int foo = 0;
auto c = [&] () { return foo++; };
assert((f<decltype(c), callback>(0) == 0));
}

This means that a compile would need to provide some extra "extension"
flag to allow it in non-strictly conforming mode.

HTH & Greetings from Bremen,

Daniel Krügler
0 new messages