My previous question concluded that a distasteful "double cast" might be necessary to use the POSIX makecontext with a C++ lambda function (i.e. function object). Moving on, I'm now faced with a compilation error relating to the following minimal code:
#include <iostream>
#include <ucontext.h>
using namespace std;
template <typename T> void foo() {
ucontext_t c;
auto f = [=](int i){ cout << i << endl; };
makecontext(&c, (void (*) (void)) (void (*)(int)) f, 1, 12345);
}
int main(int argc, char *argv[]) {
foo<int>();
return 0;
}
The error is:
error: invalid cast from type ‘foo() [with T = int]::<lambda(int)>’ to type ‘void (*)(int)’
However, if I remove the unused (in this example) template argument from the foo function, so it becomes void foo();, and change the call to foo() the error disappears. Could someone tell me why? I'm using G++ 4.6.
Edit:
From the comments below, it seems the [=] in the code above causes the lambda to be a "capturing" lambda, regardless of the fact that it doesn't actually capture anything. The [=] is not necessary in my code, alas replacing with [] in GCC 4.6 does not remove the error. I am installing GCC 4.6.1 now...
If you use [=] to induce your lambda, you will not get a function pointer (or an object that is convertible to one). You will get a function object. And no amount of casting is going to allow you to pass that to makecontext. Not in any way that actually works.
According to N3291, the most recent working draft of C++0x:
The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.
This is the only place where the specification allows conversion to a function pointer. Therefore, if recent versions of GCC do allow conversion to function pointers for [=], that not in accord with the specification.
Only captureless lambdas are convertible to function pointers; while f technically does not capture anything, it does have a default capture mode of capturing by value (for no apparent reason).
Change [=] to [] in the declaration of f and it should work as expected.
EDIT: The fact that this compiles with more recent versions of GCC (as noted by Kerrek) gives a strong indication that this is merely a compiler bug in the version you're using.
Related
Have a look at the code example listed below, I tested it with Compiler explorer (using gcc and clang) and it works and prints out the (expected) output of 200.
What I am trying to figure out: why exactly is this valid C++. Or is it not?
Here, I'm using the using keyword to define an alias (instead of a typedef) for the function type ft, which describes functions that take an int as argument and return an int (ft is a function type, not a function pointer type!). The equivalent typedef syntax is typedef int ft(int);. Since the C++ standard says that for every typedef there is an equivalent form using the using syntax, it is clear that using ft = int(int) is a well-defined way to specify this function type.
Now comes the interesting part: I use the type ft to specify the argument type of another function (print_it), and then call it, passing a lambda function. My question is: where/how does the C++ standard say that this should actually work? I think it is a wonderfully simple way to pass lambdas around. That this works is not clear to me, as a lambda is really a functor, not a function in the strict sense. So I think it is not clear that this lambda matches the type ft and therefore can be passed to print_it (if ft was defined to be std::function<int(int)> it would be clear though).
The code example:
#include <iostream>
using ft = int(int);
void print_it (ft f, int a)
{
std::cout << f(a) << std::endl;
}
int main ()
{
auto my_lambda = [] (int a) -> int { return 2 * a; };
print_it (my_lambda, 100);
return (0);
}
My question is: where/how does the C++ standard say that this should actually work?
This is specified in [expr.prim.lambda.closure]/7, which specifies that a lambda's closure type has a conversion function to a function pointer type matching the lambda's parameter and return types if the lambda is non-generic and doesn't have any capture. Calling through this function pointer basically behaves as if the lambda body was just a normal function to which the pointer points, which is possible because there are no captures which could give the lambda a state that a normal function can't have.
This applies here and you are using the conversion operator to implicitly convert the lambda object to a function pointer when passing it to print_it. This works since the lambda's parameter and return type matches the ft type and a function type used as type of a function parameter is adjusted to a pointer-to-function type instead. (See [dcl.fct]/5 for the last part.)
For generic lambdas there is a conversion function template (see the following standard paragraph). For lambdas with a capture there is no such conversion function and therefore this wouldn't work for them.
This only works because your lambda does not capture. A capture-less lambda can be converted to a C-style function pointer but a captureing lambda cannot.
I was amazed to find out that GCC allows functions to return arrays when trailing return type is used instead of normal one. As you probably knows arrays can't be copied so this is quite limited but let me show you some cool example.
#include <iostream>
#include <typeinfo>
using namespace std;
auto func() -> int [5]
{
return {4, 56, 78, 4, 0};
}
int main()
{
cout << func()[2] << endl;
cout << typeid(func).name() << endl;
}
Is this a compiler bug or some new feature?
Interestingly 'typeid' returns 'FA5_ivE' which is demangled as 'int (()) [5]' and this means exactly what you think an function returning array of 5 int's.
EDIT: I tried bounding the returned array into rvalue reference but without any success (used most of the possible forms):
auto &&refArrayTemp{ func() };
Seems that this extensions is rather useless.
This was a bug in gcc (fixed as of 2017-07-03), caused by inconsistent treatment of trailing-return-types.
First note the difference in error message between two attempts to declare a function returning a function:
using Fv = void();
Fv f1(); // error: 'f1' declared as function returning a function
auto f2() -> Fv; // error: function return type cannot be function
The first error comes from decl.c, handling declarators, while the second is a lot deeper into the internals, from tree.c, attempting to build the function type preparatory to generating code.
Trailing-return-types are handled in decl.c 30 lines below the above error - too late to catch it with the above error code, and it is not handled separately.
With arrays, similarly using a trailing-return-type allows us to skip the checks in decl.c, the difference being that function-returning-array is actually valid in terms of gcc's internal representation.
Note that you can't do much with it; gcc doesn't allow you to assign, reference-bind, decay or pass the result of func() to another function:
auto a1 = func();
// error: invalid use of non-lvalue array
auto& a2 = func();
// error: invalid initialization of non-const reference of type 'int (&)[5]' from an rvalue of type 'int [5]'
auto&& a3 = func();
// error: lvalue required as unary '&' operand
Indeed, even your code is rejected at -Wpedantic:
warning: ISO C++ forbids subscripting non-lvalue array
Finally, by exploiting a similar bug (qualifiers are stripped from scalars before handling of trailing-return-types) we can create a function with type int const volatile():
int const volatile g1(); // warning: type qualifiers ignored on function return type
auto g2() -> int const volatile; // OK!!
Latest draft, [dcl.array]/p10:
Functions shall not have a return type of type array or function, although they may have a return type of
type pointer or reference to such things. There shall be no arrays of functions, although there can be arrays
of pointers to functions.
This could be a non-standard GCC extension. It doesn't compile in the trunk version of clang. However, this may also be a bug since it has inconsistent behavior with a non-trailing return type.
Consider this C++11 code:
#include <functional>
#include <cstdlib>
template <typename F>
void test(F &&f) {
auto foo = [f]() {
f();
};
foo();
}
int main() {
test(std::bind(std::puts, "hello"));
return 0;
}
GCC and Clang accept this as valid C++11 code, but Visual Studio 2013 requires the lambda to be declared mutable (auto foo = [f]() mutable { ... }). Otherwise I get this error:
error C3848: expression having type 'const std::_Bind<true,int,int (__cdecl *const )(const char *),const char (&)[6]>' would lose some const-volatile qualifiers in order to call 'int std::_Bind<true,int,int (__cdecl *const )(const char *),const char (&)[6]>::operator ()<>(void)'
Is Visual Studio right to reject this code without mutable, or is it valid C++11?
(Curiously Clang rejects the code if you change std::bind(std::puts, "hello") to std::bind(std::exit, 0) apparently because it considers noreturn to make the function type different; I'm quite sure this is a bug.)
This isn't really about lambdas.
#include <functional>
#include <cstdlib>
int main() {
const auto x = std::bind(std::puts, "hello");
x();
}
This is accepted by GCC, but rejected by MSVC.
The standard is unclear on whether this is valid, IMO. The return value g of std::bind has an unspecified return type for which g(...) is valid and defined in terms of the cv-qualifiers of g, but the standard doesn't actually say that any operator() must be callable for const-qualified objects or references. It strongly implies that this is intended to be valid, because otherwise the reference to g's cv-qualifiers seems useless, but it doesn't actually say it is valid.
Because of that, I think MSVC's behaviour is not what the standard's authors intended, but it may nonetheless conform to what the standard requires.
This looks like a bug in the Visual Studio implementation of bind, returning a type with only a non-const function call operator. It should return a type that forwards all function calls to the bound function object, regardless of its own cv-qualifications.
To summarise the rather opaque language of C++11 20.8.9.1.2, function calls on the result of bind should be forwarded to the bound function object, and so should be allowed if calls on that object would be allowed. So it would be an error if the bound function object weren't callable if const; but here, being a function pointer, it is callable regardless of cv-qualifications.
Does it possible to invoke a procedure via pointer? I haven't found anything about it on the internet, but the following experimental code compiles without warnings.
#include <iostream>
#include <ctime>
using namespace std;
void PrintCurrentClock()
{
cout<<clock()<<endl;
}
void PrintCurrentTimeStamp()
{
cout<<time(0)<<endl;
}
int main()
{
void* pF = PrintCurrentClock;
pF;
pF = PrintCurrentTimeStamp;
pF;
system("Pause");
return 0;
}
The output is empty, as if the *pF was somewhat "transparent".
Both C and C++ have function pointers that let you do what you are looking for:
void (*pf)(void);
pf = FunctionWithVeryVeryVeryLongNameThatPrintsTheCurrentClockStateUsingStdCoutOutputStream;
pf();
The void in parentheses is optional.
The reason you did not find anything on the topic is that for historic reasons both functions and procedures in C are called functions (the reason is that there were no void in the original language - procedures returned int by default, and the return value was ignored). C++ inherited this naming convention.
What you want are function pointers:
void (*pF)() = PrintCurrentClock;
pF();
(some people argue that writing &PrintCurrentClock is better style)
Notice that, as you can see, function pointers have a quite awkward syntax (especially if you start to have function pointers with "strange" arguments) and can prevent some compiler optimizations to work correctly, so they are usually used only when actually needed (e.g. for callbacks, although in C++ functors are often preferred).
Why does your code compile, although it doesn't work as expected? In
void* pF = PrintCurrentClock;
PrintCurrentClock is a void (*pF)(), which is implicitly converted to void *1; then, writing
pF;
you are evaluating the expression pF and discarding its return value - which is effectively a no-op (exactly as if you wrote 5; or any other expression that does not involve a function call).
Actually, this conversion shouldn't happen automatically, since the C++ standard do not provide an implicit conversion from function pointers to void *. Compiling this with g++ 4.6 correctly produces the errors:
matteo#teolapmint ~/cpp $ g++ -Wall -Wextra -ansi -pedantic testfuncptr.cpp
testfuncptr.cpp: In function ‘int main()’:
testfuncptr.cpp:19:20: error: invalid conversion from ‘void (*)()’ to ‘void*’ [-fpermissive]
testfuncptr.cpp:21:15: warning: statement has no effect [-Wunused-value]
testfuncptr.cpp:23:22: error: invalid conversion from ‘void (*)()’ to ‘void*’ [-fpermissive]
testfuncptr.cpp:25:23: warning: statement has no effect [-Wunused-value]
testfuncptr.cpp:27:39: error: ‘system’ was not declared in this scope
which tells you that those conversions are not admitted, that the pF; instructions are no-ops and that you forgot #include <cstdlib> (although system("pause"); is not portable anyway).
Your way of creating and using the function pointer is slightly off. Here's an example of how to do it:
void proc() {
cout << "Hello from proc" << endl;
}
...
void (*pproc)() = proc;
pproc();
Yes you can:
Though the type-system is a bit convoluted.
So it is usual to wrap a pointer to a function in a typedef.
typedef <returnType> (*<TypeName>)(<ParameterList>);
// In your case:
tpyedef void (*PtrToTimeFunc)();
// Now your pointer types look like normal variables:
PtrToTimeFunc pf = &PrintCurrentTimeStamp;
// Calling them is like normal:
pf(); // If it needed parameters then put them as normal.
Because the C++ compiler can not past function pointers to optimize the code; in C++ it is common to use functors. A functor is an object that behaves like a function, but because it is an object can also contain state (like a closure in other languages).
struct MyFunctor
{
// To make a functor just override the operator ()
// You can make it return any type and take any parameters (just like a function).
int operator()() const
{
return time(NULL);
}
// Add any state and constructors etc. you like here.
// Though note: because I declared the operator() as const you
// can not mutate the state via the function call (remove cost)
// if you want to do that.
};
// declaring a functor just like any-other object.
MyFunctor myFunctor;
// calling. Just like a function.
myFunctor();
OK. So why is this more useful than a pointer.
When used with the standard algorithms. You define the algorithm with the type of the functor thus the compiler generates the algorithm code it also has available all the code for the functor (unlike the function pointer which it can not optimize past). This allows the compiler to do a full set of optimizations in place.
std::generate(cont.begin(), cont.end(), myFunctor);
So in C++ 11 we have introduced lambdas. These are basically functions that can be defined in place. But it is easier to think of lambdas as compiler generated functors (as they can capture the current state as part of their definition).
std::generate(cont.begin(), cont.end(), [](){return time(NULL);});
// [] - defines the state that is being captured.
// Think of this like the constructor capturing objects.
// In this case take no state.
//
// () - parameter list
// In this case no parameters
//
// {} - The code.
A more interesting example:
std::vector<int> data; // fill vector
std::for_each(data.begin(), data.end(), [](int& value){value += 4;}); // Add 4 to each member.
Suppose I have a function that performs some side effect and then returns an answer:
int foo()
{
perform_some_side_effect();
return 42;
}
I want to bind foo to a function pointer, but I'm not interested in the answer, just the side effect:
void (*bar)() = foo;
However, this appears to be a type error:
error: invalid conversion from ‘int (*)()’ to ‘void (*)()’
What is the rationale behind that error? Why doesn't the type system allow me to ignore the answer?
On a side note, it works if I wrap the function pointer in a std::function:
std::function<void()> baz = foo;
How does std::function (apparently) manage to circumvent this restriction in the type system?
What is the rationale behind that error? Why doesn't the type system allow me to ignore the answer?
The reason is that the types are different, and the generated code at the place of call (through the function pointer) is different. Consider a calling convention where all arguments are written to the stack and space for the return value is also reserved in the stack. If the call goes through a void (*)() then no space will be reserved in the stack for the return value, but the function (unaware of how it is being called) will still write the 42 to the location where the caller should have reserved space.
How does std::function (apparently) manage to circumvent this restriction in the type system?
It does not. It creates a function object that wraps the call to the actual function. It will contain a member like:
void operator()() const {
foo();
}
Now when the compiler processes the call to foo it knows what it has to do to call a function that returns an int and it will do so according to the calling convention. Because the template does not return, it will just ignore the value --that was actually returned.
std::function need only be source compatible- that is, it can generate a new class which generates new caling code that ignores the result. The function pointer must be binary compatible and cannot do that job- void(*)() and int(*)() point to the exact same code.
You can think of std::function<> doing this for your particular case:
void __func_void()
{
foo();
}
It's actually a bit more complicated than that, but the point is that it generates template code together with type-erasure to not care about the specifics.
In addition to what others have been saying, the caller also need the return type to know what destructor it should invoke on the result (the return value may be a temporary).
Unfortunately it is not as easy as
auto (*bar)() = foo;
Although GCC and Clang accept this. I need to recheck the spec to see whether that's actually correct.
Update: The spec says
The auto type-specifier signifies that the type of a variable being declared shall be deduced from its initializer or that a function declarator shall include a trailing-return-type.
This can be misleading when read fast, but this is implemented by GCC and clang to only apply to the toplevel declarator. In our case, this is a pointer declarator. The declarator nested in it is a function declarator. So just substitute auto for void and then the compiler will deduce the type for you.
By the way, you can always make this work manually, but it takes some trickery to make it work
template<typename FunctionType>
struct Params;
template<typename ...Params>
struct Params<void(Params...)> {
template<typename T>
using Identity = T;
template<typename R>
static Identity<R(Params...)> *get(R f(Params...)) {
return f;
}
};
// now it's easy
auto bar = Params<void()>::get(foo);