Lambda 作为类朋友,仅限受保护成员访问

问题描述

考虑以下代码库设计模式:

template<typename T>
class Foo {
public:
    Foo(T t) : class_member_{t} {}
    const T class_member() const { return class_member_;}
    
    Foo(const Foo& other ) {
        class_member_ = other.class_member_;
    }

    Foo& operator=(const Foo& other) {
        class_member = other.class_member_;
        return *this;
    }

    template<template<class> class U,typename V>
    friend auto extend(U<V>& u,V v);

    void update_from_hidden() {
        class_member_ = hidden_member_;
    }
protected:
    T hidden_member_{class_member_ + 1};
    

private:
    T class_member_;
    void update_class_member(T new_val) { class_member_ = new_val;}    
};

template<template<class> class T,typename U>
auto extend(T<U>* tt,U val) {
    auto impl = [] (T<U>* t,U val) {
        t->hidden_member_ += 5; // okay I want this lambda to be able to
                              // modify Foo::hidden_member
        t->class_member_ = 7; // Invalid,I don't want this lambda to have
                              // access to Foo's private members
        return *t;
    };
}

int main() {
    Foo<int> foo(3);
    foo = extend(&foo,2);
    return foo.class_member();
}
    

现在,lambda 主体中的这两行和 main 中的这一行:

t->hidden_member_ += 5;
t->hidden_member_ = 7;
// main 
foo = extend(&foo,2);
   

不会编译,因为这些成员在此上下文中受保护和私有,并且 operator=() 无法解析值 2

在尝试保留此代码结构的同时,我希望通过某个任意类对象的友元函数的这些类型的 lambda 能够直接访问类的受保护成员,同时仍然限制它们访问类的私有成员和两个变量和私人功能。

这是否可以实现,如果可以,我至少需要对此类和/或 lambda 执行哪些操作才能实现此行为?

如果没有,是否还有其他适合该模型的现有代码模式?

我想将特定方法抽象到类之外,但我更喜欢在此上下文中使用 lambda。事实上,我更希望有这样的东西,但这不是我所知道的有效 C++ 代码......

class Bar {
public:
      Bar(int val) : member_{val} {
protected:
      int hidden_;
private:
      int member_;
};

auto extend = [](Bar* bb,int val) {
    friend class Bar; // not valid or legal as far as I know
    bb->hidden_ += 3; // I want this to be valid
    bb->member_ = 5; // I want this to be blocked,not valid
    
    return *bb;
};

这是我遇到障碍的地方...我关心的不是方法的实现,而是类 Foo 和 lambda extend 如何通过朋友或我上面描述的方式和上下文中的其他一些机制......不知道在这里做什么。


-编辑-

好的,这是一个用例场景。

假设我有一个 WaterPipe 类,它具有只能在类本身内更改的私有成员。它有一些更新方法可以在内部更改该私有成员。现在,它具有受保护的成员,这些成员不能被类的外部访问,但希望将它们暴露给 lambda 来修改这个类的维度或状态,而不是它的内部属性或行为。

class WaterPipe {
public:
    WaterPipe(float length,float diameter) 
    : length_{length},diameter_{diameter},has_changed{false} 
    {
        calculate_props();
    } 

    friend extend(WaterPipe* pipe,float newLength,float newDiameter);

    const auto length() const { return length_; }
    const auto diameter() const { return diameter_; }
    const auto volume() const { return volume_flow_; }
    const auto direction() const { return direction_flow_; }
    const auto pressure() const { return pressure_flow_; }

protected:
    float length_;
    float diameter_;
    void recalculate() { calculate_pops(); }
 private:
    float volume_flow_;
    float direction_flow_;
    float pressure_flow_;

    void calculate_props() {
        // implementation here
    }
};

auto extend_water_pipe(WaterPipe* pPipe,float newDiameter) {
    bool changed = false;
    auto impl = [](WaterPipe* pipe,float newDiameter)
        if (pipe->length_ != newLength || pipe->length_ != newDiameter) {               
            pipe->length_ = newLength;
            pipe->diameter_ = newDiameter;
            pipe->recalculate();
             changed = true;
        }
        return pipe;
    };

    if ( !changed ) { return pPipe; }

    return impl(pPipe,newLength,newDiamter)();  
}

在一些 GUI 应用程序中:

void object_construction_in_app(...) {
    // user grabs water pipe drawing tool
    // user clicks point on graph node and holds mouse down
    // drags it in some direction,stops and releases the mouse
    // this calls the constructor on the pipe giving it the length
    // the diameter was already set via the `water pipe drawing tool`
    
    // create a new pipe object here with specified values
    // and store it into some container to be rendered.        
}

// some frames later
void object_update(...) {
    // user selects already constructed pipe
    // and decides to either change it's diameter through context menu
    // or changes its length by clicking on one of its ends and starts
    // to drag it again... 

    // get object from container and use `friend function - lambda`
    // to update it's dimensions,return back that object to have
    // it be rendered,store it into some other container,such as
    // a queue,etc... 
}

水管将计算它自己的内部值...外部朋友 lambda 将仅通过重置长度或直径并调用受保护的 recalculate() 函数来访问它的受保护成员,然后调用该类的内部私有calculate_props() 函数。然后 lambda 要么返回一个指向类对象的指针,要么返回一个指向该类的顺从指针以允许进行复制或赋值。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...