2014-11-22 7 views
2

'const'& 'const가 아닌'객체에서 액세스 할 수있는 멤버 함수를 정의하는 방법이 있습니까?'const'와 'non-const'객체 모두에서 인스턴스화 할 수있는 유니버설 멤버 함수 정의

sList 목록 클래스 구현에 필요합니다. 그것에서 나는 매개 변수로 다른 함수를 'const'또는 'non-const'포인터를 sList으로 취하고 현재 sList 구조의 각 목록에 대해 호출 할 함수를 선언하려고합니다. 나는 결국 너무 람다 전달하려는 때문에 내가 auto pFunc을 사용하고

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; 
}; 

:

여기에 선언합니다. 그래서 지금 내가이 타입의 const 객체를 가지고 있고 그것으로부터 'DoForEachList'를 호출하면 'auto'타입으로부터 1 arg를 가진 인자 λ 함수로 전달됩니다. 코드가 DoForEachList를 호출

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]

그리고 : 제 컴파일러는 같은 실패합니다

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

friend 함수 템플릿과 어쩌면 두 개의 멤버 함수 래퍼를 사용할 수 있습니다. – dyp

+0

아주 간단합니다. - const가 아닌 객체는 언제나 'const' 참조에 바인딩 할 수 있지만 다른 방법으로는 사용할 수 없습니다. 그것은 암시 적 변환 (한정 변환)입니다. 흠. 그것은 당신이 실제로 const가 아닌 객체에서 호출 할 때 객체를 수정하고 싶다면 쓸모가 없습니다. 이 경우 두 개의 함수를 작성하십시오. – Deduplicator

+0

같은 몸으로 - 아,이게 최선의 방법인가요? 래퍼 함수를 ​​사용하는 것은 해결책이 아닙니다. 왜냐하면 'pFunc'인수가 잘못 추론 될 것이기 때문입니다 ('this'에 const_cast를 사용하여 'const'멤버 함수에서 'non-const'호출을 감싸면 람다 함수 arg가 ' sList * '잘못되었습니다). – AnArrayOfFunctions

답변

6

는 의견 @dyp에 의해 대답에 빌드하려면 :

this의 constness에 과부하를 걸려면 실제로 두 개의 별도 기능이 필요합니다. 그러나 작업을 도우미 함수로 오프로드하여 중복을 최소화 할 수 있습니다.

@dyp에는 friend 함수 템플릿을 사용하는 것이 좋지만 친구 함수에는 액세스 제어가 없으므로 대신 정적 멤버 함수를 사용하는 것이 좋습니다.

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

+0

그래, 내가 'auto self'일 수 있다는 것을 알았을 때, 그것은 'self'가 포인터가되는 나의 첫 번째 제안을위한 것이고,이 경우'&&'는 전혀 유용하지 않다. 이 특별한 경우에는'self'가 참조인데, 당신이 lvalues로만 호출하기 때문에 여전히 차이가 없지만, 왜 당신이 그것을 선택했는지 볼 수있는 간단하고 유용한 충분히 일반적인 접근법입니다. :) – hvd

+0

* "친구 기능에는 액세스 제어 권한이 없습니다."* 여기서 말하는 것을 이해하지 못합니다. – dyp

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.