Lambda 表达式、共享指针和 this 的类型
Lambda expression, shared pointer and the type of this
考虑以下代码:
#include <memory>
#include <cassert>
struct S: std::enable_shared_from_this<S> {
protected:
S() = default;
int bar() { return 42; }
};
struct T: S {
static std::shared_ptr<T> create() {
return std::shared_ptr<T>(new T{});
}
auto foo() {
auto ptr = std::static_pointer_cast<T>(shared_from_this());
return [ptr](){ return ptr->bar(); };
}
private:
T() = default;
};
int main() {
std::shared_ptr<T> ptr = T::create();
auto lambda = ptr->foo();
assert(lambda() == 42);
}
上面的代码可以编译。如果方法 foo
被修改如下:
auto foo() {
// In this case, there is no explicit cast
// The type of ptr is no longer std::shared_ptr<T>
// It is std::shared_ptr<S> instead
auto ptr = shared_from_this();
return [ptr](){ return ptr->bar(); };
}
在这种情况下,代码不再编译(无论是 GCC 还是 clang)。
显然它会在转换后编译(这是我在第一个示例中所做的),但我希望即使在这种情况下 bar
对 lambda 也是可见的,因为它在其上下文中是可访问的以及 S
的部分界面。
我怀疑这是由于 5.1.5p8,特别是:
The lambda-expression's compound-statement yields the function-body [...] of the function call operator, but for [...], determining the type and value of this [...], the compound-statement is considered in the context of the lambda-expression.
其实clang返回的错误已经很清楚了:
main.cpp:8:9: note: can only access this member on an object of type T
我的推导对吗?
是否由于上述段落,从而导致 this
指针的确定类型问题与共享指针之一不匹配?
shared_ptr
参与游戏的事实让我有点难以理解。
老实说,我希望这两个示例都能编译或者都失败。
看来您只是违反了受保护访问的基本规则。 IE。整个事情与 lambdas 或共享指针无关。从一开始就存在的受保护访问的古老规则说,base class 的受保护成员只能通过派生 class 的对象访问。与您上面所说的相反,在您的上下文中,S
的受保护成员无法通过类型 S
的对象访问,但可以通过类型 T
.
的对象访问。
整个事情可以简化为以下简单示例
struct S
{
protected:
int i;
};
struct T : S
{
void foo()
{
this->i = 5; // OK, access through `T`
T t;
t.i = 5; // OK, access through `T`
S s;
s.i = 5; // ERROR: access through `S`, inaccessible
S *ps = this;
ps->i = 5; // ERROR: access through `S`, inaccessible
}
};
我认为问题中的评论有答案,我不想在这里声称功劳。
我认为您可能对 'nicer' 执行静态转换工作的方式感兴趣,而无需实际调用静态转换,甚至不需要知道基础 class:
首先定义这个有用的免费函数:
template<class T>
auto shared_from_that(T* p)
{
return std::shared_ptr<T>(p->shared_from_this(), p);
}
然后根据它获取正确键入的共享指针:
auto foo() {
return [ptr = shared_from_that(this)](){
return ptr->bar();
};
}
剧情简介:
调用 std::shared_ptr
的(看似广为人知的)2 参数构造函数,它使用 arg1 中 shared_ptr 的控制块和 arg2 中指向受控对象的指针。
考虑以下代码:
#include <memory>
#include <cassert>
struct S: std::enable_shared_from_this<S> {
protected:
S() = default;
int bar() { return 42; }
};
struct T: S {
static std::shared_ptr<T> create() {
return std::shared_ptr<T>(new T{});
}
auto foo() {
auto ptr = std::static_pointer_cast<T>(shared_from_this());
return [ptr](){ return ptr->bar(); };
}
private:
T() = default;
};
int main() {
std::shared_ptr<T> ptr = T::create();
auto lambda = ptr->foo();
assert(lambda() == 42);
}
上面的代码可以编译。如果方法 foo
被修改如下:
auto foo() {
// In this case, there is no explicit cast
// The type of ptr is no longer std::shared_ptr<T>
// It is std::shared_ptr<S> instead
auto ptr = shared_from_this();
return [ptr](){ return ptr->bar(); };
}
在这种情况下,代码不再编译(无论是 GCC 还是 clang)。
显然它会在转换后编译(这是我在第一个示例中所做的),但我希望即使在这种情况下 bar
对 lambda 也是可见的,因为它在其上下文中是可访问的以及 S
的部分界面。
我怀疑这是由于 5.1.5p8,特别是:
The lambda-expression's compound-statement yields the function-body [...] of the function call operator, but for [...], determining the type and value of this [...], the compound-statement is considered in the context of the lambda-expression.
其实clang返回的错误已经很清楚了:
main.cpp:8:9: note: can only access this member on an object of type
T
我的推导对吗?
是否由于上述段落,从而导致 this
指针的确定类型问题与共享指针之一不匹配?
shared_ptr
参与游戏的事实让我有点难以理解。
老实说,我希望这两个示例都能编译或者都失败。
看来您只是违反了受保护访问的基本规则。 IE。整个事情与 lambdas 或共享指针无关。从一开始就存在的受保护访问的古老规则说,base class 的受保护成员只能通过派生 class 的对象访问。与您上面所说的相反,在您的上下文中,S
的受保护成员无法通过类型 S
的对象访问,但可以通过类型 T
.
整个事情可以简化为以下简单示例
struct S
{
protected:
int i;
};
struct T : S
{
void foo()
{
this->i = 5; // OK, access through `T`
T t;
t.i = 5; // OK, access through `T`
S s;
s.i = 5; // ERROR: access through `S`, inaccessible
S *ps = this;
ps->i = 5; // ERROR: access through `S`, inaccessible
}
};
我认为问题中的评论有答案,我不想在这里声称功劳。
我认为您可能对 'nicer' 执行静态转换工作的方式感兴趣,而无需实际调用静态转换,甚至不需要知道基础 class:
首先定义这个有用的免费函数:
template<class T>
auto shared_from_that(T* p)
{
return std::shared_ptr<T>(p->shared_from_this(), p);
}
然后根据它获取正确键入的共享指针:
auto foo() {
return [ptr = shared_from_that(this)](){
return ptr->bar();
};
}
剧情简介:
调用 std::shared_ptr
的(看似广为人知的)2 参数构造函数,它使用 arg1 中 shared_ptr 的控制块和 arg2 中指向受控对象的指针。