gpt4 book ai didi

c++ - 如何访问模板参数的成员? "Member access to incomplete type"

转载 作者:太空狗 更新时间:2023-10-29 22:57:22 27 4
gpt4 key购买 nike

我正在尝试声明一个类“Lambdas”,它将向另一个类“Test”提供 lambda(及其类型信息)。 Lambdas 还在 lambdas 内部持有对具体测试实例的“this”引用,用于访问测试公共(public)成员。我这样做是为了定义一次 lambda,然后通过 decltype() 在其他任何地方推导类型但我收到错误:成员访问不完整类型:

template <typename T>
struct LambdasInstances {
T * self;
explicit LambdasInstances(T * p) : self(p) {} // CAPTURE Test "this"

auto genLambda1() {
return [=](int x){
self->testVar; // ERROR: Member access to incomplete type
};
}
};

class Test3 {
public:
LambdasInstances<Test3> instances;
int testVar;

Test3() : instances(this) {}

decltype(instances.genLambda1()) varLambda = instances.genLambda1();

void useLambda() { varLambda(123); }
};

但是如果我要在外部定义 genLambda(),那么我会遇到另一个问题 - 错误:在其定义之前不能使用具有推导类型的 genLambda()!:

template <typename T>
struct LambdasInstances {
T * self;
explicit LambdasInstances(T * p) : self(p) {}
auto genLambda1(); // would be defined after Test3 declaration
};


class Test3 {
public:
int testVar;
LambdasInstances<Test3> instances;
Test3() : instances(this) {}
decltype(instances.genLambda1()) varLambda = instances.genLambda1();
};

// IF WE DEFINE AFTER :: ^ genLambda() with deduced type cannot be used before its defined!
template< typename T>
auto LambdasInstances<T>::genLambda1() {
return [=](int x){
self->testVar;
};
}

最佳答案

编译器可能需要整个可用类型的定义才能知道成员的偏移量(例如,在表达式 self->testVar 中,编译器必须知道 testVar), 但它可能无法知道特定成员的偏移量,直到它获得整个定义,因为编译器必须知道你的结构/类的对齐方式(我什至猜测一些在计算成员之间的填充时可能涉及不直接的逻辑)在所有成员都知道之后,请参阅 this ,这完全是特定于编译器和平台的。

回到你的问题。您告诉编译器以 genLambda1 作为成员来定义 Test3,这是一个必须知道成员 testVar 的偏移量的 lambda。看起来很容易,对吧?但是 testVar 的偏移量取决于整个 Test3 的定义(请参阅上面的段落)- 这里我们处于循环中。

你会说:“嘿愚蠢的编译器,我只给出了一个指向 lambda 的指针,而不是一个你必须知道 `Test3 的整个大小的按值复制,你为什么要阻止我这样做?”。这是一个合理的问题,因为理论上编译器可以稍后解析偏移量,但似乎编译器不够聪明。标准说:

The lambda-expression’s compound-statement yields the function-body (8.4) of the function call operator ...

这基本上是说 lambda 主体是函数主体,但在函数主体中你不能有不完整的类型,对吧? Lambda 对 C++ 来说相对较新,并没有详细说明所有的极端情况,所以我们希望在未来某个时候这个问题会得到解决,当然编译器会比标准更复杂。

对于您的问题,我看到了以下解决方案:

template <typename T>
struct LambdasInstances {
explicit LambdasInstances(T* p) : _lambda([=](int x) { return p->testVar; }) {}

auto genLambda1() { return _lambda; }

private:
std::function<void(int)> _lambda;
};

class Test3 {
public:
int testVar;
LambdasInstances<Test3> instances;

Test3() : instances(this) {}

decltype(instances.genLambda1()) varLambda = instances.genLambda1();
};

int main() {
Test3 test3;
Test3* test3_ptr;
LambdasInstances<Test3> instances(&test3);
auto lambda = [=](int x) { return test3_ptr->testVar; };
std::function<void(int)> functor = lambda;
cerr << sizeof(Test3) << endl;
cerr << sizeof(LambdasInstances<Test3>) << endl;
cerr << sizeof(lambda) << endl;
cerr << sizeof(functor) << endl;
return 0;
}

不同之处在于,std::function 为您提供了一个抽象级别,可以保护 LambdasInstances::genLambda1 类型不受 Test3 定义的影响>。不幸的是,正如您将从 main 输出中看到的那样,该函数比 lambda 占用更多的内存。如果这不能满足您的需求,我建议您修改设计,也许您会在 lambdas 时代之前的旧好技术中找到一些东西。

关于c++ - 如何访问模板参数的成员? "Member access to incomplete type",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44345233/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com