This code fails to compile under VS2010:
#include <functional>
using namespace std;
void test()
{
auto f = [] (int) {};
bind(f, 10);
}
It gives a long error pointing to the internals of bind implementation.
If I switch to a normal function instead of a lambda, the bind works fine, so I believe this is a bug in VS2010 but maybe I'm missing something.
Can you help me?
It seems VC10 cannot cope with lambdas as arguments to std::bind. It seems to expect either a function pointer or a function object. I don't know whether this is a bug, but I suspect it is, since lambda function should become function objects during compilation.
Anyway, if you are in need of a workaround, this compiles for me:
std::function<void(int)> func = [] (int) {};
std::bind(func, 10);
Related
Came across an interesting issue today started by my own typo. I created a lambda that takes in a reference to a struct and incorrectly set it to a std::function that receives it's argument by value.
Here's a more concise version:
#include <functional>
struct InputStruct
{
int i;
InputStruct(): i(1){}
};
void function_rcv(std::function<bool(InputStruct)> & func_ref)
{
InputStruct in;
func_ref(in);
}
int main()
{
std::function<bool(InputStruct)> my_func = [](InputStruct & in)->bool{return in.i==1;};
function_rcv(my_func);
}
Checking with godbolt shows this compiles successfully with MSVC, but fails for both Clang and GCC.
Interestingly enough, using a primitive instead of a struct fails compilation on all three compilers.
Is this a bug in the MSVC compiler?
In summary: it is not a compiler bug. MSVC accepts this code because of its default non-conforming behavior, but it can be made standard-conforming with a switch.
First of all, I need to clarify std::function's one aspect: it accepts a function (in general, Callable) which signature is not a perfect match, but the parameters can be converted. Consider:
using intFn = void (int);
void fn(short);
intFn *a = fn; // doesn't compile
std::function<intFn> b = fn; // compiles!
Here, intFn a function type which has an int parameter, while the function fn has a short parameter. The simple function pointer a, cannot be set to point to fn, as the type of the parameter differ (int vs short). But, std::function allows this, so b can be set to point to fn.
In your example, std::function has an InputStruct parameter by value, while the lambda has a non-const lvalue reference InputStruct &. When std::function std::forwards its parameter, it becomes an xvalue, which cannot be bound to the lambda's lvalue reference parameter. That's why standard conforming compilers don't accept this code.
Why does MSVC accept this code? Because it has non-conforming behavior by default: it allows binding class temporaries (and xvalues) to non-const lvalue references. You can disable this behavior with /Zc:referenceBinding (or the older /Za option). If you use this switch, MSVC rejects your example.
What I'm trying to do is eat exceptions when constructing an object that may be invalid. It'd be perfect for use of std::optional, but I don't believe the omission of std::optional changes the error I see: the object is being captured and used before it's been initialized. I don't believe it should be captured in the first place because we haven't reached a sequence point to the best of my knowledge (does a lambda initialization count as a sequence point?). Moreover, the bug is IMO easily catchable human error (and even does get caught... depending upon circumstances).
How (more importantly, why) is the lambda able to capture and use the not-yet-initialized foo?
https://godbolt.org/g/IwcHrV
#include <string>
using namespace std;
void foo() {
string foo = [&]()->string{
// using foo before it's been initialized == undefined behavior
auto guessed_foo = to_string(1234);
if ( begin(foo) == end(foo) ) {
return guessed_foo;
}
return {};
}();
}
Compiler exited with result code 0
But... replacing the declaration of string foo with auto foo does appear to cause an error similar to what I'd like to see.
https://godbolt.org/g/GfE4WH
#include <string>
using namespace std;
void foo() {
auto foo = [&]()->string{
auto guessed_foo = to_string(1234);
if ( begin(foo) == end(foo) ) {
return guessed_foo;
}
return {};
}();
}
error: variable 'foo' declared with 'auto' type cannot appear in its own initializer
Note that I found this using GCC 6.2 on Ubuntu 16.04 LTS. The configuration in Godbolt is using clang 3.9.1. Both are configured for c++14.
So my questions are:
Why is the lambda capture for an initialization of a non-auto-declared variable able to capture and use the (not-yet-initialized) variable?
Why does auto get (in my opinion, correctly) caught and errored?
Moreover, why the difference between the above two? It sounds like compiler bugs, but... is there something specific in the standard declaring this to be correct behavior?
This could be taken as an argument for auto keyword?
The second snippet runs into [dcl.spec.auto]/10:
If the type of an entity with an undeduced placeholder type is needed
to determine the type of an expression, the program is ill-formed.
The type of foo is needed to determine the type of the expression foo within the lambda body, but at that point you haven't deduced foo's type yet, so the program is ill-formed.
As to why you are allowed to capture something before its initialization, see generally Why is 'int i = i;' legal?. We have many examples of recursive lambdas using std::function:
std::function<void(int)> foo = [&foo](int i){ return foo(i - 1); };
I would like to create a std::function bound to a member function taking a rvalue argument. Here is my attempt which does not compile ("xxfunction(154): error C2664: ... You cannot bind an lvalue to an rvalue reference" among others).
class C
{
public:
void F(std::string &&s)
{
//do something with s
}
C(){}
};
C c;
std::function<void(std::string&&)> pF = std::bind(&C::F,&c,std::placeholders::_1);
//somewhere far far away
pF(std::string("test"));
I did some reading and I think it has to do with std::function no using perfect forwarding but I cant figure out how to get it to work.
Edit:
std::function<void(std::string&)> pF = [&c](std::string&in){c.F(std::move(in));};
This is a semi viable work around but it is not perfect because calling pF will work with an lvalue now and move it anyway.
std::string s("test");
pF(s);
auto other = s; //oops
It seems your std::bind implementation does not support perfect forwarding via placeholders, but since you have C++11 and std::bind is ugly anyways, use lambdas:
std::function<void(std::string&&)> pF
= [&c](std::string&& str)
{
c.F(std::move(str));
};
Edit:
Note: Although accepted, this answer is not a solution to the problem at hand, because it is not std::bind but MSVC10's std::function implementation that is flawed. However, the suggestion has led to a workaround and therefore was accepted by PorkyBrain.
I've been trying to pass a std::vector to a function by reference with default value being an empty std::vector. The declaration of my function looks as follows:
void function( std::vector<double>& vec=std::vector<double>(0));
The definition of my function is:
void function( std::vector<double>& vec)
{
...
}
However my C++ compiler (gcc 4.6) is throwing an error here, saying:
error: default argument for parameter of type ‘std::vector&’ has type ‘std::vector’
I've seen this version of the code compile fine on a Microsoft VS 2010 compiler. And I'm wondering if this is an issue of different c++ standard interpretation between gcc and vs2010.
You can't. You can't bind a temporary to a ref-to-non-const, so you could only do this:
void function(const std::vector<double>& vec = std::vector<double>());
In your case, then, I suggest function overloading:
void function(std::vector<double>& vec)
{
// ...
}
void function()
{
std::vector<double> v;
function(v);
}
If you don't like the extra function call then you're out of luck. :)
I don't know whether C++11 rvalue refs might help here, if you have access to them.
I've seen this version of the code compile fine on a Microsoft VS 2010 compiler. And I'm wondering if this is an issue of different c++ standard interpretation between gcc and vs2010.
MSVS has a tendency to allow you to bind temporaries to refs-to-non-const, which is non-standard behaviour. GCC is correct.
You can do the following:
namespace{
auto empty_vec = std::vector<double>();
}
void function(std::vector<double>& vec=empty_vec);
then you do not have to change the signature of your function. But you have to define the variable empty_vec instead. I put it in an unnamed namespace to make it invisible from outside this translation unit.
But the drawback is (as LightnessRacesinOrbit noted below) that within this translation unit the value of empty_vec can be changed, which might break your function.
You can't pass temporary object as nonconst lvalue-reference!
Add const qualifier or remove default argument.
The following method makes it clear what the default value is -- and it can be replaced with other default behaviors.
static std::vector<double> emptyVectorProvider()
{
return (std::vector<double>());
}
void function (std::vector<double>&& = emptyVectorProvider ());
void function2 (std::vector<double>&& def = emptyVectorProvider ())
{
function(std::forward<std::vector<double> > (def));
}
I would like to pass a lambda to a funciton.
This
boost::function<void()> fncPtr(boost::bind<void>([](){/* something */}));
works, but if the lambda had a parameter, I don't know how to do it properly:
boost::function<void(bool)>
fncPtr(boost::bind<void,bool>([](bool){/* something */}, _1));
does not work.
Where I am wrong?
How to pass lambda with argument(s)?
I would like to do this in a member function.
So in "global scope"(is it the name?) this method above works fine.
This works fine for me with GCC4.5:
#include <boost/bind.hpp>
#include <boost/function.hpp>
int main() {
boost::function<void(bool)>
fncPtr(boost::bind<void>([](bool){/* something */}, _1));
}
It doesn't need the type of the parameters. Those parameter types could be templated anyway (for some functors), so in general it cannot depend on them. It only needs the return type.
Incidentally, it even works for me when I pass <void, bool>, but only when the lambdas has no captures. I think that this may work for me because GCC4.5 supports conversion of lambdas to function pointer types, when the lambdas has no capture clause. <void, bool> would make bind have a candidate that accepts a function pointer, and make the lambda convert to that. Your compiler apparently doesn't support that special conversion yet (but the FDIS requires it).
So, just pass <void> only, and it should work.
I summed up some techniques here on Ideone. Note, I used the C++0x versions, the Boost ones should work just fine too.
It really depends though on what your function wants as a parameter though. If it is simply templated or takes a (std::|boost::)function, then a simple lambda will do. No need for complicated binding or packaging in an extra (std::|boost::)function.
You have a problem in the compiler probably. I have an error in Visual Studio 2010 too. You can help compiler to convert a lambda to a function using helper function:
template <typename T>
void closureToFunction(bool x){ T f; return f(x); }
int main()
{
auto exp = [](bool x){/* something */};
boost::function<void(bool)> fncPtr(
boost::bind( closureToFunction<decltype(exp)>, _1) );
return 0;
}