如何访问模板参数的成员?“成员访问不完整的类型”

How to access the member of a template parameter's? "Member access to incomplete type"

本文关键字:成员 访问 类型 参数 何访问      更新时间:2023-10-16

我正在尝试声明一个" lambdas"类,该类将向其他类"测试"提供lambdas(及其类型信息(。Lambdas还将"此"引用到Lambdas内部的混凝土测试实例,以访问测试公共成员。我这样做是为了一次定义lambdas,然后通过dectType((推导其他任何地方的类型但是我会遇到错误:成员访问不完整类型:

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(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的偏移(,但是,在获得整个定义之前,它可能无法知道特定成员的偏移,因为编译器必须知道您的结构/类的对齐方式(我什至猜测,计算计算时可能涉及一些不直发的逻辑在所有成员知识之后,会员之间的填充,请参见这一点,这完全是编译器和平台。

所以回到您的问题。您告诉编译器将Test3定义为genLambda1为会员,这是必须知道成员testVar的偏移的lambda。似乎很容易,对吧?但是testVar的偏移取决于整个Test3的定义(请参阅上面的段落( - 我们在循环中。

您会说:"嘿,愚蠢的编译器,我只给指针指向lambda,而不是按价值副本,您必须知道`test3的整体尺寸,为什么要阻止我这样做?"一个合法的问题,因为从理论上讲,编译器可以稍后解决偏移,但似乎编译器不够聪明。标准说:

lambda-expression的化合物陈述产生了功能呼叫操作员的功能体(8.4(...

基本上说兰伯达体是功能主体,但是在功能主体中,您不能拥有不完整的类型吗?Lambdas对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时代之前的旧技术中找到一些东西。