2014-11-22 77 views
2

有没有一种方法来定义可以从'const'&'非const'对象访问的成员函数?通用成员函数定义,可从'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个参数。我的编译器将失败的东西,如:

error: passing const sList<unsigned char> as this argument of void sList<T>::DoForEachList(auto:1) [with auto:1 = main()::<lambda(sList<unsigned char>*)> ; T = unsigned char ]' discards qualifiers [-fpermissive]

和代码调用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); 
    } 

    //... 
}; 
+2

您可以使用朋友函数模板,也可以使用两个成员函数包装器。 – dyp 2014-11-22 22:04:27

+0

非常简单 - 一个非const对象总是可以绑定到一个'const'引用,但不是相反。这是一个隐式转换(合格转换)。嗯。如果你真的想修改对象,但是如果你在一个非const对象上调用它,那就没用了。在这种情况下,只需编写两个函数。 – Deduplicator 2014-11-22 22:06:15

+0

身体一样 - 呃,这是最好的方法吗?使用包装函数不是一个解决方案,因为那么'pFunc'参数会被错误地推导出来(如果我们在'const'成员函数中使用const_cast'this'包装'非const'调用,那么lambda函数arg将被推断为' sList *'这是错误的)。 – AnArrayOfFunctions 2014-11-22 22:26:31

回答

6

要通过@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); 
    } 
}; 
+0

@ hvd谢谢。有了'auto &&',你也可以在ref修饰符上重载'DoForEachList',而不是在这种情况下有很大的区别。 – Oktalist 2014-11-22 23:02:13

+0

是的,当我注意到它可能是'auto self'时,那是我第一次提出'self'是指针的提示,在这种情况下'&&'根本没有用处。在这种特殊情况下,'self'是一个参考,它仍然没有什么区别,因为你只是用左值来调用它,但这是一个简单而有用的一般方法,我可以看出为什么选择它。 :) – hvd 2014-11-22 23:10:17

+0

*“朋友功能没有访问控制。”*我不明白你在这里说什么。 – dyp 2014-11-22 23:17:39

0

你应该只使用const成员函数,使成员变量mutable,它告诉编译器/你该成员不影响“过气,改变“这个班的行为。如果情况并非如此,请重新考虑您的设计,因为这不太正确。 mutable更准确,例如,地图的关键需求,在这样的,它并没有在地图上影响排序的方式进行修改,但即使是这样......

代码示例:

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

int main() 
{ 
    const Bla bla; 
    bla.increment(); 
} 

Live demo here