Why my VS2010 can't compile this code:
#include <functional>
#include <vector>
int main()
{
std::vector<int> vec;
std::bind(&std::vector<int>::push_back, std::ref(vec), 1)();
return 0;
}
You should be more specific why this doesn't seem to work for you.
#include <iostream>
#include <tr1/functional>
#include <vector>
int main(int argc, char* argv[]) {
std::vector<int> vec;
std::tr1::bind(&std::vector<int>::push_back, std::tr1::ref(vec), 1)();
std::cout << "vec.size = " << vec.size() << std::endl;
std::cout << "vec[0] = " << vec[0] << std::endl;
return 0;
}
$ gcc -o test -lstdc++ test.cpp && ./test
vec.size = 1
vec[0] = 1
Update: Luc Danton is right, the issue here is the overloaded push_back. See question Are there boost::bind issues with VS2010 ?. Also, note that the issue is not limited to push_back, see Visual Studio 2010 and boost::bind.
The bottom line is that what you're trying to do isn't possible in portable C++. std::vector<>::push_back is guaranteed to be overloaded in C++11 compilers, as at a minimum there must be an overload for lvalues and an overload for rvalues.
Usually, when taking the address of an overloaded member function, §13.4/1 in the C++11 FDIS tells us that we can control which overload we're taking the address of thusly:
A use of an overloaded function name without arguments is resolved in certain contexts to a function, a pointer to function or a pointer to member function for a specific function from the overload set. A function template name is considered to name a set of overloaded functions in such contexts. The function selected is the one whose type is identical to the function type of the target type required in the context. [ Note: That is, the class of which the function is a member is ignored when matching a pointer-to-member-function type. —end note ] The target can be
an object or reference being initialized,
the left side of an assignment,
a parameter of a function,
a parameter of a user-defined operator,
the return value of a function, operator function, or conversion,
an explicit type conversion, or
a non-type template-parameter.
The overloaded function name can be preceded by the & operator. An overloaded function name shall not be used without arguments in contexts other than those listed. [ Note: Any redundant set of parentheses surrounding the overloaded function name is ignored. —end note ]
The problem comes from §17.6.5.5/2:
An implementation may declare additional non-virtual member function signatures within a class by adding arguments with default values to a member function signature; hence, the address of a member function of a class in the C++ standard library has an unspecified type.
Consequently, it is not portable to ever take the address of a standard library class member function, as the type of such an expression is by definition unknowable except on an implementation-by-implementation basis.
Luc Danton's proposed workaround (specifically, using a lambda) is also what I would recommend:
std::vector<int> vec;
[&](){ vec.push_back(1); }();
Try this:
struct push_back {
void
operator()(std::vector<int>& vector, int i) const
{
vector.push_back(i);
}
};
// somewhere else:
std::vector<int> vec;
std::tr1::bind(push_back(), std::tr1::ref(vec), 1)();
With C++03 note that push_back cannot be a local type; with C++11 it can but it would be more idiomatic (and completely equivalent) to use a lambda.
In all likeliness your implementation provides overloads for std::vector<T>::push_back and thus its address would have to be disambiguated. If this is what happened, your compiler should have provided you with an appropriate error message. In all cases, you should explain what you mean by "it's not possible".
The point is not to use such helper
functions. – magenta
Then why didn't you put it in the question? I can't read your mind.
You can also try this:
std::vector<int> vec;
void (std::vector<int>::*push_back)(int const&) = &std::vector<int>::push_back;
std::tr1::bind(push_back(), std::tr1::ref(vec), 1)();
Which I believe is not guaranteed to success.
It should propably lok like this:
std::vector<int> vec;
std::tr1::bind(&std::vector<int>::push_back, std::tr1::ref(vec), _1)(1);
Related
I wondered if it is valid to use std::function with incomplete type, e.g. in case of forward declaration. I wrote this small code:
#include <iostream>
#include <functional>
struct S;
std::function<S(void)> m;
struct S {
S() { std::cout << "ctor\n"; }
~S() { std::cout << "dtor\n"; }
void foo() { std::cout << "foo\n";}
};
S goo() {
return S{};
}
int main() {
m = goo;
m().foo();
}
Even though the S is incomplete in the point of declaring m, I could declare return type like a complete type(a non-pointer return type). This code complies and works correctly, but I'm not sure if this code is valid by standard. Because you cannot forward declare return type if it is not a pointer in a normal function(so I cannot forward declare S for goo()).
Any idea if this is a valid code by standard or not?
Any idea if this is a valid code by standard or not?
The program is well-formed because even though S is incomplete at the point of the definition std::function<S(void)> m;, the std::function doesn't place any requirement on S to be a complete type and instead requires that S be the name of a return type.
From std::function's documentation:
The function class template provides polymorphic wrappers that generalize the notion of a function pointer. Wrappers can store, copy, and call arbitrary callable objects, given a call signature, allowing functions to be first-class objects.
The above means that the template argument should be in the form of a call signature. From call signature's documentation:
A call signature is the name of a return type followed by a parenthesized comma-separated list of zero or more argument types.
(emphasis mine)
As we can see the above requires that S be the name of a return type. That is, it doesn't explicitly place any requirement on S being complete.
In other words, S in your given examples satisfies this condition so that it is valid.
The following code snippet:
#include <iostream>
void does() { std::cout << "do" << std::endl; }
void does(bool b = false) { std::cout << "do(bool)" << std::endl; }
void fwd(void (*func)(bool))
{
func(false);
}
int main(int, char**)
{
fwd(&does);
fwd(does);
fwd(*does);
}
understandably produces the following error:
test.cpp:15:10: error: overloaded function with no contextual type information
The compiler cannot discern which of the functions I intend to use.
What I don't understand is why the code will correctly run when I comment out the line that reads:
fwd(*does)
Why can the compiler suddenly resolve the ambiguousness?
int main(int, char**)
{
fwd(&does);
fwd(does);
}
Also, without overloading does the snippet will correctly run with all 3 calls.
This snippet runs fine...
#include <iostream>
void does(bool b = false) { std::cout << "do(bool)" << std::endl; }
void fwd(void (*func)(bool))
{
func(false);
}
int main(int, char**)
{
fwd(&does);
fwd(does);
fwd(*does);
}
I'm compiling this with gcc 4.6.3 on a Linux box.
Thanks for the help!
The answer to your question is in the overload-resolution rules for functions.
Specifically, there is an exception for using & before the function-name (once) not breaking overload-resolution, but none for using *.
Also see that only one of those two functions accept that single argument:
13.4 Address of overloaded function [over.over]
1 A use of an overloaded function name without arguments is resolved in certain contexts to a function, a pointer to function or a pointer to member function for a specific function from the overload set. A function template name is considered to name a set of overloaded functions in such contexts. The function selected is the one whose type is identical to the function type of the target type required in the context. [ Note: That is, the class of which the function is a member is ignored when matching a pointer-to-member-function type. —end note ] The target can be
an object or reference being initialized (8.5, 8.5.3),
the left side of an assignment (5.17),
a parameter of a function (5.2.2),
a parameter of a user-defined operator (13.5),
the return value of a function, operator function, or conversion (6.6.3),
an explicit type conversion (5.2.3, 5.2.9, 5.4), or
a non-type template-parameter (14.3.2).
The overloaded function name can be preceded by the & operator. An overloaded function name shall not be used without arguments in contexts other than those listed.
Quote is from n3242 (c++11), with bold by me.
fwd expects a function that takes a boolean parameter; you only have one such version of does, so there is no confusion. In effect, does and &does are considered the same (because functions cannot be values, one of these two should technically be incorrect if not impossible to represent, but the language has to chosen to instead just treat them as the same thing).
But when you try to use fwd(*does), you would need a definition of does that dereferences to such a function, and you don't have anything like that -- in fact, as I have been recently schooled, you can't have anything like that.
Example:
#include <functional>
int main() {
auto test = []{};
test = []{};
return 0;
}
This emits the following error message in gcc 4.7.2:
test.cpp: In function ‘int main()’:
test.cpp:5:13: error: no match for ‘operator=’ in ‘test = <lambda closure object>main()::<lambda()>{}’
test.cpp:5:13: note: candidate is:
test.cpp:4:16: note: main()::<lambda()>& main()::<lambda()>::operator=(const main()::<lambda()>&) <deleted>
test.cpp:4:16: note: no known conversion for argument 1 from ‘main()::<lambda()>’ to ‘const main()::<lambda()>&’
From the standard 5.1.2.3 (emphasis mine):
An implementation may define the closure type differently from what is described below provided this does not alter the observable behavior of the program other than by changing:
— the size and/or alignment of the closure type,
— whether the closure type is trivially copyable (Clause 9)
— whether the closure type is a standard-layout class (Clause 9), or
— whether the closure type is a POD class (Clause 9).
As far as I can tell, this is what I'm running up against. It's attempting to use a deleted assignment operator and failing. I am curious to know if there's an easy workaround, and more broadly what the motivating rationale for allowing copy constructibility to be omitted for lambdas generally.
You seem to think that those two lambdas have the same type, but that is not true. Each one creates its own type:
#include <functional>
#include <type_traits>
#include <iostream>
int main() {
auto test = []{};
auto test2 = []{};
std::cout << std::is_same< decltype( test ), decltype( test2 ) >::value << std::endl;
return 0;
}
will print 0. Of course the error message you are getting from the compiler could be a little bit clearer in this regards...
The type of the
lambda-expression
(which is also the type of the closure object) is a unique, unnamed non-
union class type
So it is like you are doing the following:
struct {} a;
struct {} b;
a = b; // error, type mismatch
Use std::function if you want to assign different lambdas with the same signature to the same variable.
std::function<void()> f = []{};
f = []{}; //ok
Lambda can't be redefined because each lambda is of a different, anonymous, incompatible type.
They can be copied only if you pass them to a templated function (like std::function ctor) that would be able to deduce that type.
The reason you are not able to do this is because the copy assignment operator for the lambda-expression is declared deleted, See section 5.1.2/20 of the standard. For a more clear (for unusual definitions of clear) see this code sample
template<class T> void f(T x1)
{
T x2 = x1; // copy constructor exists, this operation will succeed.
x2 = x1; // assignment operator, deleted and will cause an error
}
int main()
{
f([]{});
return 0;
}
Other answers have pointed out that each lambda has a unique type, but this is not the reason why you are getting that error. This example shows that even if the two lambdas have the same type, it still is not able to copy it. However you are able to copy it to a new variable. This is the reason your error message is complaining about missing operator= and not about their types being different. Although each lambda having it's own type does not help you out much either.
If we could assign one lambda to another lambda of a different type, how do we copy the function bodies/definitions from that lambda to the other one? If we would be so stubborn, then we could use some member std::function-like type to be the one who will be copied. But that would be against the ol' C++ rule of not paying blah blah...
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.
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.