模板化类可以在lambda中捕获自己的this
指针:
template <typename T>
class Foo {
public:
void foo(void) {}
auto getCallableFoo(void) {
return [this]() { this->foo(); };
}
};
可以使用以下代码测试此示例和所有其他Foo
示例:
int main()
{
Foo<int> f;
auto callable = f.getCallableFoo();
callable();
}
但是,如果使用init-capture,则不再适用于GCC:
auto getCallableFoo(void) {
return [ptr = this]() { ptr->foo(); };
}
错误消息(来自GCC 5.1):
error: ‘Foo<T>::getCallableFoo()::<lambda()>::__ptr’ has incomplete type
Clang 3.7似乎编译并运行此代码而没有错误。 (我实际上使用的是3.7版本之前从源代码编译的版本,但我不认为从那以后它已经破了。)
初始捕获应该像auto
的赋值一样,但是以下代码似乎在GCC中没有错误地工作:
// New method in Foo:
auto getPtr(void) {
return this;
}
// Usage:
auto ptr = f.getPtr();
ptr->foo();
那么为什么ptr
值无法在GCC中捕获this
?这是一个错误吗?
另一个考虑因素是,according to CppReference,this
被视为与其他所有捕获列表类型分开的语法案例。因此,这可能是为什么海湾合作委员会以不同方式处理这些案件的一个暗示。但是我不清楚对这个特殊情况做了什么(如果有的话)特殊处理,或者为什么它只是一个特例。
编辑: 的工作似乎
:return [ptr = static_cast<decltype(this)>(this)]() { ptr->foo(); };
这对我没有意义,因为decltype
(与auto
不同)推断完全其参数的类型,因此static_cast
实际上不应该影响任何事情。
编辑2,3,4:以下是我用两个编译器尝试过的完整表达式列表,其中的注释表明哪些编译器接受每个表达式:
[this]() { this->foo(); }; // Both: work
[ptr = this]() { ptr->foo(); }; // GCC fails
[ptr = static_cast<decltype(this)>(this)]() { ptr->foo(); }; // Both: works (!!!)
[ptr(this)]() { ptr->foo(); }; // GCC fails
[ptr{this}]() { ptr->foo(); }; // GCC works (!!!!!!!!), Clang doesn't work (infers initializer list)
[ptr = {this}]() { ptr->foo(); }; // Both: fail (infers initializer list)
[ptr = &*this]() { ptr->foo(); }; // Both: work
[ptr = &*(this)]() { ptr->foo(); }; // Both: work
对于[ptr{this}]
,我的Clang版本(预发布3.7版)警告说,解释会改变;目前它推断出初始化列表,但可能更晚的版本将(或已经)推断出this
in accordance with the new auto
rules from N3922的类型。
GCC允许[ptr{this}]
而不是[ptr(this)]
令我感到震惊。我对此没有任何解释。
答案 0 :(得分:5)
这是一个错误。我已就此问题提交了a GCC bug report。它现在已经fixed in GCC's trunk。
正如Revolver_Ocelot所述,&*
似乎迫使g++
执行正确的类型扣除。因此,我当前的解决方法(在宏内部采用可能为this
的指针表达式)捕获[ptr = &*(ptr_expr)]
。
如上所述,海湾合作委员会的Jason Merrill已经在GCC的主干中解决了这个问题。他评论this
指针需要在lambda捕获中进行特殊处理;具体而言,它被视为不是依赖类型。以前,此特殊处理适用于[this]
,但不适用于[ptr = this]
。