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));
| ~~~^~~~~~~~~~~~~~~~~~
The return type of client::foo
is void
, and you're assigning the return values of it to the two lambda
s. The variable name lambda
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 call foo
anymore. Since the intention is to call foo
via the pointer conv_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
, the this->
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 the conv_ptr
pointer, since conv_ptr->foo()
does not mean the same thing as foo()
(which is equivalent to this->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));
}