2009-10-22 5 views
1

추가 기능을 제공하기 위해 일련의 추가 기능 템플릿으로 장식 할 수있는 클래스가 있습니다. 각 애드온에는 기본 클래스가 알아야 할 식별 addon_value가 있습니다.템플릿 메타 프로그래밍 OR 작업

아래 코드는 내가하고 싶은 예제입니다. 분명히, main() 함수는 컴파일에 실패합니다. 목표는 CBase :: GetValueOfAddOns()가 각 애드온의 addon_value를 OR 연산하는 값을 알고있는 것입니다. 실제로 GetValueOfAddOns()에서 계산을 수행 할 필요는 없으며 결과에 도달 할 수 있어야합니다. 어떤 도움

template< class T > 
class AddOn_A : public T 
{ 
public: 
    AddOn_A(int x) : T(x) 
    {}; 

    enum { addon_value = 0x00000001 }; 
}; 

template< class T > 
class AddOn_B : public T 
{ 
public: 
    AddOn_B(int x) : T(x) 
    {}; 

    enum { addon_value = 0x00000010 }; 
}; 

class CBase 
{ 
public: 
    explicit CBase(int x) : x_(x) 
    { 
     // error LNK2001: unresolved external symbol "public: virtual int __thiscall CBase::GetValueOfAddOns(void)const " ([email protected]@@UBEHXZ) 
     int z = GetValueOfAddOns(); 
    }; 

    virtual int GetValueOfAddOns() const = 0; 

private: 
    int x_; 
}; 

// define an empty AddOn 
template<class> class empty 
{ 
public: 
    enum { addon_value = 0x00000000 }; 
}; 

// forward declaration and Add-On defaults 
template< template<class> class AddOn1 = empty, 
      template<class> class AddOn2 = empty, 
      template<class> class AddOn3 = empty > 
class CMyClass; 

// specialized template for the default case 
template<> class CMyClass< empty, empty, empty > : public CBase 
{ 
public: 
    CMyClass(int x) : CBase(x) 
    {}; 

    enum { addon_value = 0x00000000 }; 
}; 

// actual definition 
template< template<class> class AddOn1, 
      template<class> class AddOn2, 
      template<class> class AddOn3 > 
class CMyClass : public AddOn1<CBase>, 
       public CMyClass< AddOn2, AddOn3 > 
{ 
public: 
    CMyClass(int x) : AddOn1<CBase>(x), 
         CMyClass< AddOn2, AddOn3 >(x) 
    {}; 

    enum { addon_value = AddOn1<CBase>::addon_value | CMyClass< AddOn2, AddOn3 >::addon_value }; 

    int GetValueOfAddOns() const 
    { 
     return addon_value; 
    } 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    CMyClass<AddOn_A> A(0); 
    _ASSERT(A.GetValueOfAddOns() == AddOn_A<CBase>::addon_value); 

    CMyClass< AddOn_A, AddOn_B > AB(0); 
    _ASSERT(AB.GetValueOfAddOns() == (AddOn_A<CBase>::addon_value | AddOn_B<CBase>::addon_value)); 

    return 0; 
} 

감사합니다, PaulH

+3

생성자 또는 소멸자에서 가상 메서드를 호출 할 수 없습니다. 이것은 정의되지 않은 동작입니다. –

+0

@Martin York - 그럼, CBase ctor()에서 addon_value를 얻는 방법이 있습니까? 아니면 무리한가? – PaulH

+1

Martin York : 가상 함수를 호출하는 것이 순수하지 않은 한 괜찮습니다. 사람들을 혼란스럽게하는 유일한 단점은 그들이 구축 된 가장 파생 된 객체를 가리킬 뿐이라는 것입니다. 거의 항상 호출이 사실상 가상이 아니라는 것을 의미합니다. 마찬가지로 소멸자 - 소멸자를 완료하지 않은 가장 많이 파생 된 객체가 호출됩니다. – coppro

답변

2

확실하지 않음이 가장 우아한 방법이지만, 다음은 매우 간단합니다 :

이 CmyClass에서이 추가 :

enum {AddonsValues = AddOn1<CBase>::addon_value | CMyClass<AddOn2, AddOn3>::AddonsValues}; 

int GetValueOfAddOns() 
{ 
    // return the result of OR-ing the addon_value of each add-on. 
    return AddonsValues; 
}; 

을이 전문 CMyClass<empty, empty, empty>에 :

enum {AddonsValues = 0}; 
+0

나는 몰라. 적어도 나머지 코드보다 우아합니다. 나는 그것을 좋아한다. :) – PaulH

1

당신이 virtual 그 기능이 순수 할 경우, 당신은 당신이 사용할 수있는 모든 정보를 CMyClass, 그것을 구현할 수 있습니다. empty 클래스를 변경하여 enum { addon_value = 0x00000000 };을 정의하면 더 쉽게 사용할 수 있습니다.

+0

That + Eric의 작품 위의 의견 CBase()가 여전히 값을 "알"수 없다는 점을 제외하고는 훌륭합니다. 원래 게시물의 코드를 수정하여 링커 오류를 표시했습니다. CBase :: ctor에서 GetValueOfAddons()에 액세스하려고 시도합니다. 어떤 제안? 감사합니다. – PaulH

+0

왜 CBase의 ctor에서이 함수를 호출하고 싶습니까? 가상 기능은 대부분의 사람들이 ctors 및 dtors에서 기대하는 방식으로 작동하지 않습니다.그것은 단지 ctor 인 경우, 값을 인수로 전달할 수 있습니다. 그렇지 않으면 가상 기능이 작동합니다. – sbi

0

더 잘 보자 :

새로운 질문보기 bout the problem with hierarchy here 거기에 AddOnValues ​​문제도 해결되어 템플릿 메타 프로그래밍이 필요 없습니다.

관련 문제