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