Using a this pointer in a generic lambda capture - c++

I have an issue in which Clang (3.6) and G++ (5.1) have a differing opinion:
#include <functional>
struct X
{
X()
{
std::function<void (int)> f = [this](auto x){foo(x);};
}
void foo(int x){}
};
int main(){}
Clang accepts this, whereas G++ states:
error: cannot call member function ‘void X::foo(int)’ without object
Both compilers accept it if I call this->foo(x) directly instead, but I'd rather know who's right.
Note: both the "auto" in the lambda signature and the conversion to a std::function<> are required to trigger this case.

Both compilers accept it if I call this->foo(x) directly instead, but I'd rather know who's right.
Considering it compiles in gcc 5.2, clang is the one correct in your specific case. It looks like it was just a bug in gcc 5.1. gcc 6.0 also compiles this fine.
Plus it makes intuitive sense, this should be implied.

Related

Argument siliently dropped by std::bind? [duplicate]

I was interested in learning more about the behaviour of std::bind() with member functions, and thought it was odd for MSVC to compile the following code when no other compiler I tried would. Is MSVC wrong to compile this?
I tried GCC, CLang, and some other minor compilers in the compiler explorer side-by-side with MSVC: https://godbolt.org/z/DNtP-o
Only MSVC would compile this:
#include <functional>
struct S{
void f(int){}
};
int main(){
S s;
auto binding = std::bind(&S::f,s, 5,3);
return 0;
}
These are the errors I get from compiling with 'x86-64 clang 8.0.0':
error: static_assert failed due to requirement 'integral_constant<bool, false>::value ? sizeof...(_BoundArgs) >= integral_constant<unsigned long, 1>::value + 1 : sizeof...(_BoundArgs) == integral_constant<unsigned long, 1>::value + 1' "Wrong number of arguments for pointer-to-member"
error: no matching function for call to 'bind'
None of the compilers are wrong here, since the program has undefined behavior.
Note that MSVC does of course give errors if you actually try to call the bound functor. So the question is fairly academic, since in a real program using std::bind to create something that can never be called on any code path is not very useful.
C++17 [func.bind.bind]/2 says:
Requires: ... INVOKE(fd, w_1, w_2, ..., w_N) shall be a valid expression for some values w_1, w_2, ... w_N, where N has the value sizeof...(bound_args). ...
But this is a requirement on code using the standard library, not on implementations (compilers and/or libraries), and nothing says implementations must diagnose a violation. Violating a Requires: paragraph is undefined behavior unless otherwise noted.
So the ability of g++ and clang++ (when using libstdc++) to notice the problem at the std::bind call is just a nice quality of implementation bonus feature.
Presumably libstdc++ does this by template matching on a pointer to (member) function. But in the more general case, determining whether there might be any way to call a functor with a given number of arguments of wildcard types is more difficult or impossible. All three compilers accept this code with no errors or warnings:
#include <functional>
struct X {
void operator()() const;
void operator()(int) const;
};
void f() {
auto func = std::bind(X{}, 2, 3, 4);
static_cast<void>(func);
}

Why does std::bind accept more arguments than possible for bound function?

I was interested in learning more about the behaviour of std::bind() with member functions, and thought it was odd for MSVC to compile the following code when no other compiler I tried would. Is MSVC wrong to compile this?
I tried GCC, CLang, and some other minor compilers in the compiler explorer side-by-side with MSVC: https://godbolt.org/z/DNtP-o
Only MSVC would compile this:
#include <functional>
struct S{
void f(int){}
};
int main(){
S s;
auto binding = std::bind(&S::f,s, 5,3);
return 0;
}
These are the errors I get from compiling with 'x86-64 clang 8.0.0':
error: static_assert failed due to requirement 'integral_constant<bool, false>::value ? sizeof...(_BoundArgs) >= integral_constant<unsigned long, 1>::value + 1 : sizeof...(_BoundArgs) == integral_constant<unsigned long, 1>::value + 1' "Wrong number of arguments for pointer-to-member"
error: no matching function for call to 'bind'
None of the compilers are wrong here, since the program has undefined behavior.
Note that MSVC does of course give errors if you actually try to call the bound functor. So the question is fairly academic, since in a real program using std::bind to create something that can never be called on any code path is not very useful.
C++17 [func.bind.bind]/2 says:
Requires: ... INVOKE(fd, w_1, w_2, ..., w_N) shall be a valid expression for some values w_1, w_2, ... w_N, where N has the value sizeof...(bound_args). ...
But this is a requirement on code using the standard library, not on implementations (compilers and/or libraries), and nothing says implementations must diagnose a violation. Violating a Requires: paragraph is undefined behavior unless otherwise noted.
So the ability of g++ and clang++ (when using libstdc++) to notice the problem at the std::bind call is just a nice quality of implementation bonus feature.
Presumably libstdc++ does this by template matching on a pointer to (member) function. But in the more general case, determining whether there might be any way to call a functor with a given number of arguments of wildcard types is more difficult or impossible. All three compilers accept this code with no errors or warnings:
#include <functional>
struct X {
void operator()() const;
void operator()(int) const;
};
void f() {
auto func = std::bind(X{}, 2, 3, 4);
static_cast<void>(func);
}

Why does this incorrect std::function initialization compile using MSVC?

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.

ref qualifier gives error in gcc4.7.2 and vc10

consider the below minimal example.
#include<iostream>
struct A
{
A(){std::cout<<"def"<<'\n';}
void foo()&{std::cout<<"called on lvalue"<<'\n';}
};
int main()
{
A a;
a.foo();
A().foo();
return 0;
}
this gives error about expecting ';' at the end of declaration and and expected un-qualified-id before '{'.
Can i know what i'm doing wrong? in the actual code i want to avoid calling the non-static member function through temporaries.
tried on gcc 4.7.2 and vc2010.
Thanks.
The answer will be short: VC10 and GCC 4.7.2 do not support ref-qualifiers.
However, notice that your foo() function has an lvalue ref qualifier, meaning that you cannot invoke it on temporaries.
If you want this expression to compile as well:
A().foo();
Then you should use const&, or provide an overload for &&, as in this live example.
To work with ref-qualifiers you can use Clang 3.2 or GCC 4.8.1.

Template function causes a compiler error when used with local lambda

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.