If I capture the "this"-ptr in a lambda I can call member functions without problems. However, when I instead capture the pointer explicitely (without mentioning "this"), it stops working. Am I doing something wrong? According to my understanding, the pointers should be the very same, so this really surprised me. Is there some compiler magic going on to treat "this" in a special way?
#include <cstdio>
#include <string>
struct client
{
auto foo(std::string&& other)
{
printf("%s!\n", other.data());
}
void local()
{
std::string str = "Hello World this is a sentence to long for sso!";
auto lambda = [this, other = std::move(str)]() mutable {
foo(std::move(other));
}();
}
static auto external(void* ptr) {
std::string str = "Hello World this is a sentence to long for sso!";
client* conv_ptr = static_cast<client*>(ptr);
auto lambda = [conv_ptr, other = std::move(str)]() mutable {
foo(std::move(other));
}();
}
};
int main()
{
client c1;
c1.local();
client::external(static_cast<void*>(&c1));
}
Yields:
<source>:15:14: error: 'void lambda' has incomplete type
15 | auto lambda = [this, other = std::move(str)]() mutable {
| ^~~~~~
<source>: In lambda function:
<source>:25:16: error: cannot call member function 'auto client::foo(std::string&&)' without object
25 | foo(std::move(other));
| ~~~^~~~~~~~~~~~~~~~~~
CodePudding user response:
The return type of
client::foo
isvoid
, and you're assigning the return values of it to the twolambda
s. The variable namelambda
is confusing, since the right hand side of the assignment is actually an immediately invoked lambda expression, not just a lambda.In the second lambda, since
this
is not captured, the compiler does not have a way to callfoo
anymore. Since the intention is to callfoo
via the pointerconv_ptr
, use it explicitly.To quote from Lambda expressions on cppreference:
For the purpose of name lookup, determining the type and value of the
this
pointer and for accessing non-static class members, the body of the closure type's function call operator or operator template is considered in the context of the lambda-expression.Therefore, for class members that are accessible by
this->member_name
, thethis->
part can be omitted, as it can also be omitted in the context of the lambda-expression, which is within a member function of the class. However, this does not apply to theconv_ptr
pointer, sinceconv_ptr->foo()
does not mean the same thing asfoo()
(which is equivalent tothis->foo()
) in the context.
To make the code compile, remove the invocations ()
from both lambdas, and call foo
using conv_ptr->foo
.
#include <string>
struct client
{
auto foo(std::string&& other)
{
printf("%s!\n", other.data());
}
void local()
{
std::string str = "Hello World this is a sentence to long for sso!";
auto lambda = [this, other = std::move(str)]() mutable {
foo(std::move(other));
};
}
static auto external(void* ptr) {
std::string str = "Hello World this is a sentence to long for sso!";
client* conv_ptr = static_cast<client*>(ptr);
auto lambda = [conv_ptr, other = std::move(str)]() mutable {
conv_ptr->foo(std::move(other));
};
}
};
int main()
{
client c1;
c1.local();
client::external(static_cast<void*>(&c1));
}