通用成员函数定义,可从 'const' 和 'non-const' 对象实例化

Universal member-function definition, instanceable from both 'const' & 'non-const' objects

本文关键字:const non-const 对象 实例化 成员 定义 可从 函数      更新时间:2023-10-16

有没有办法定义一个既可以从"const"和"non-const"对象访问的成员函数?

我需要这个来sList列表类的实现。在其中,我想声明一个函数,该函数将另一个具有"const"或"non-const"sList指针的函数作为参数,并将为当前sList结构中的每个列表调用它。

以下是它的声明:

template <typename T>
struct sList
{
    sList(initializer_list<T>);
    inline void DoForEachList(auto pFunc)
    {
        for(auto p = this; p; p = p->pNext)
            pFunc(p);
    }
    ~sList();
    T dat;
    sList *pNext = nullptr;
};

我正在使用auto pFunc因为我也想最终传递 lambda。所以现在如果我有一个这种类型的 const 对象并从它调用"DoForEachList"作为参数 lambda 函数传递,从类型"auto"中传递 1 个参数。我的编译器将失败,如下所示:

错误:将const sList<unsigned char>作为void sList<T>::DoForEachList(auto:1)的参数传递this [auto:1 = main()::<lambda(sList<unsigned char>*)> ; T = unsigned char ]' 丢弃限定符 [-允许]

调用DoForEachList的代码

void main()
{
    extern const sList<unsigned char> cvobj;
    cvobj.DoForEachList([] (auto pCurr) {/* Do something */});
}

有没有办法像这样定义DoForEachList成员函数(或成员函数的模板):

template <typename T>
struct sList
{
    inline void DoForEachList(auto pFunc) auto //either 'const' or none
    {
        for(auto p = this; p; p = pNext->pNext)
            pFunc(p);
    }
    //...
};

要在评论中@dyp答案的基础上再接再厉:

如果您想重载this的恒定性,您确实需要两个单独的函数。但是,您可以通过将工作卸载到帮助程序函数来最大程度地减少重复。

@dyp建议为此使用友元函数模板,但友元函数没有访问控制,所以我通常更喜欢静态成员函数;然后你可以把它设为私有或受保护:

template <typename T>
struct sList
{
    void DoForEachList(auto pFunc)
    {
        DoForEachListHelper(*this, pFunc);
    }
    void DoForEachList(auto pFunc) const
    {
        DoForEachListHelper(*this, pFunc);
    }
private:
    static void DoForEachListHelper(auto&& self, auto pFunc)
    {
        for(auto p = &self; p; p = pNext->pNext)
            pFunc(p);
    }
};

你应该只使用 const 成员函数并使成员变量mutable,它告诉编译器/你成员不会影响类的"已更改"行为。如果不是这种情况,请重新考虑您的设计,因为这不太正确。 mutable更正确的地方,例如地图的键需要修改,使其不会影响该地图中的顺序,但即便如此......

代码示例:

struct Bla
{
    void increment() const { i++; }
private:
    mutable int i = 0;
};
int main()
{
    const Bla bla;
    bla.increment();
}

现场演示在这里。

相关文章: