2014-06-24 1 views
0

지금까지 내가 가진 :DLL에 클래스 카운터를 구현하는 방법은 무엇입니까?

// TypeCounter.h 

template <typename Base> 
class Counter : public Base 
{ 
protected: 
    static int typeIndexCounter; 
}; 

template <typename T, typename Base> 
class Bridge : public Counter<Base> 
{ 
public: 
    virtual ~Bridge() {} 

    virtual int GetTypeIndex() const 
    { 
     return TypeIndex(); 
    } 

    static int TypeIndex() 
    { 
     static int typeIndex = typeIndexCounter++; 
     return typeIndex; 
    } 
}; 

// static variable definition 
template <typename Base> 
int Counter<Base>::typeIndexCounter; 

사용 사례 같은 것입니다 : Base 클래스의 각 종류에 따라서

class SBase 
{ ... } 
class S0 : public Bridge<S0, SBase> 
{ ... } 
class S1 : public Bridge<S1, SBase> 
{ ... } 
class S2 : public Bridge<S2, SBase> 
{ ... } 

, 내가 이제까지 인스턴스화 된 경우 (이이 파생 얼마나 많은 믿을 수있는, 당연하지).

문제는이 Counter 클래스가 DLL에 있다는 것입니다.

나는이 DLL의 여러 사용자가있는 경우, 각 사용자는 자신의 인스턴스를 것 BridgeCounter은 다음 TypeIndex() 같은 T 이러한 사용자들 사이에 다를 수 있습니다. (사용자 측 매크로를 정의하여, importexport을 바꿀 것)

나는 CounterBridge 이전 __declspec(dllexport)을 넣어하려고했으나 사용자 측에서 컴파일 오류가 있습니다.
오류에도 불구하고 클래스 템플릿을 내보내지 않아야하므로 잘못된 접근입니다.

그래서 내가 어떻게 이것을 달성 할 수있는, 같은 T 많은 인스턴스화가있는 경우에도 TypeIndex() 특정 T에 대해 동일하게 유지 있는지 확인하려면?

감사합니다!

+0

'Counter' 클래스를 DLL에 넣을 수 없습니다. DLL은 템플릿이기 때문에 템플릿은 헤더 파일에만 남기 때문에 범위는 컴파일 단위입니다. 'Counter' 템플릿의 인스턴스화 *를 다른 컴파일 유닛에 넣을 수는 있지만, DLL에서 그것들을 내보낼 수 있는지 확신 할 수 없습니다. –

답변

0

지도를 사용하여 정보를 저장하십시오. 이것은 인라인 코드를 포함하지 않으며 (CRTP mixin을 제외하고 계산하고 계산), 다른 부분이 동기화되지 않도록해야합니다.

즉, "사용자"라고 쓰면 사용자가 로그인 한 사용자라는 의미는 아닙니다. 이유는 이것이 하나의 프로세스 내에서 항상 하나의 카운트이며 동일한 또는 다른 사용자에 의한 다른 프로세스가 이것에 아무런 영향을 미치지 않는다는 것입니다.

+0

예, "사용자"는 "프로젝트"를 의미하며 카운트는 단일 프로세스에서 일관됩니다. 어떤 종류의지도를 제안합니까? 열쇠와 가치는 무엇입니까? –

+0

'map '입니다. 어쩌면 당신은'typeid'를 사용하여 더 작은 것을 만들 수 있습니다.하지만 같은 클래스가 여러 바이너리에서 인스턴스화 될 때 다시 문제가 발생할 것으로 예상합니다. –

+0

좋아,'string '을'typeid (T) .name()'과'size_t'를 인덱스로 사용한다는 의미인가? –

0

클래스 템플릿을 내보낼 수 없다는 것은 사실입니다. 헤더 파일에 모든 클래스 템플릿을 작성했기 때문에이 코드는 쓸모가 없으므로 실제로 코드를 사용할 수 있어야합니다.

이 라이브러리 컴파일 헤더 파일 : 대신 클래스 인스턴스를 내 보낸 후에 "통근"키워드와 함께 사용 할

class SBase{ ... } 

template class __declspec(dllexport) Bridge<S0, SBase>; 
class S0 : public Bridge<S0, SBase> 
{ ... } 
template class __declspec(dllexport) Bridge<S1, SBase>; 
class S1 : public Bridge<S1, SBase> 
{ ... } 
template class __declspec(dllexport) Bridge<S2, SBase>; 
class S2 : public Bridge<S2, SBase> 
{ ... } 

는 그리고 이것은 헤더 파일 때입니다

class SBase{ ... } 

extern template class __declspec(dllimport) Bridge<S0, SBase>; 
class S0 : public Bridge<S0, SBase> 
{ ... } 
extern template class __declspec(dllimport) Bridge<S1, SBase>; 
class S1 : public Bridge<S1, SBase> 
{ ... } 
extern template class __declspec(dllimport) Bridge<S2, SBase>; 
class S2 : public Bridge<S2, SBase> 
{ ... } 

이제 링커는 컴파일 모듈뿐만 아니라 모든 프로그램을 통해이 클래스를 검색합니다.

같은 코드를 사용하여 서로 다른 출력을 얻기 위해, typedefed해야합니다

#ifdef LIBRARY_BUILD 
#define EXPORT __declspec(dllexport) 
#define TEMPLATE_EXPORT 
#else 
#define EXPORT __declspec(dllimport) 
#define TEMPLATE_EXPORT extern 
#endif 

class SBase{ ... } 

TEMPLATE_EXPORT template class EXPORT Bridge<S0, SBase>; 
class S0 : public Bridge<S0, SBase> 
{ ... } 
TEMPLATE_EXPORT template class EXPORT Bridge<S1, SBase>; 
class S1 : public Bridge<S1, SBase> 
{ ... } 
TEMPLATE_EXPORT template class EXPORT Bridge<S2, SBase>; 
class S2 : public Bridge<S2, SBase> 
{ ... } 

이것은 정적 멤버와 모든 템플릿 클래스에서 수행해야을, 그래서 모든 템플릿 클래스는 하나를 가지고있다 컴파일 모듈 당 하나가 아닌 구성원의 인스턴스화.

당신은 여기에 더 많은 정보를 가질 수 있습니다 classes and static variables in shared libraries

편집 : 다시 읽기 질문 (이것은 정적 멤버와 하나이기 때문에) 내가 템플릿 기본 클래스로 통근 선언 할 것,하지 특정을 사람 : 그래서 지금

TEMPLATE_EXPORT template class EXPORT Counter<SBase>; 

, 당신은 어떤 SBase의 파생 클래스를 가질 수 있으며 모든 통근으로 자신을 선언 할 필요없이, 같은 카운터 클래스에 의존한다. 물론 SBase가 라이브러리에 있으면 extern (정상적인 방법으로 템플릿이 아니기 때문에 __declspec (dllexport) 만)으로 선언해야합니다.

관련 문제