2009-07-18 2 views
2

현재 C++ 정적 라이브러리를 설계하고 있습니다. 많은 데이터 유형을 지원할 수 있도록 클래스를 generic/configuarable로 만들고 싶습니다. 내 라이브러리에 데이터 유형별 코드를 작성하고 싶지 않습니다. 그래서 수업을 templatize했습니다.C++ 라이브러리 설계

하지만 C++ "내보내기"템플릿 기능은 현재 사용중인 컴파일러에서 지원되지 않으므로 헤더 파일에 클래스의 구현을 제공해야합니다. 내 클래스의 구현 세부 사항을 내 라이브러리를 사용할 클라이언트 코드에 노출하고 싶지 않습니다.

위의 문제에 대한 디자인 대안을 제공해 주시겠습니까 ??

+0

템플릿의 구현 세부 사항을 정확히 표시하고 싶지 않은 이유는 무엇입니까? –

+0

@Neil : 헤더 파일을 사용하여 미리 컴파일 된 라이브러리를 제공하려고한다고 가정하고 헤더 파일을 제공하여 구현을 노출하고 싶지는 않습니다. 코드를 다른 사람에게 넘겨주고 싶지 않은 이유는 여러 가지가 있습니다. –

+1

@Daniel Sigh. 죄송 합니다만, 귀하의 가정 (또는 누군가)을 원하지 않습니다. OP의 이유를 원합니다. 왜 SO에 게시하는 거의 모든 사람들이 "추측"하거나 "추측"하겠다는 강한 충동을 느끼고 있습니까? –

답변

0

코드를 난독 화하려고 할 수 있지만 헤더 파일에 템플릿 코드를 포함하는 것은 C++ 03을 선택하는 데있어 거의 선택의 여지가 없습니다.

Vandevoorde는 그의 책에서 또 다른 기술을 설명합니다. Explicit instantiation -하지만 가능한 모든 유용한 조합을 명시 적으로 인스턴스화해야합니다.

그러나이 항목에 대한 가장 포괄적 인 검토는 C++ Templates : The Complete Guide의 6 장을 읽으십시오.

(귀하의 코멘트에 응답)

편집 : 당신이 사용하는 템플릿없이 일반적인 코드를 작성하는 두 가지 옵션이 있습니다
이 1) 전처리 - 여전히 헤더 파일이 필요 무효 사용
2) * - 수다 - 믿을 수 없을만큼 안전하지 않은

아니, 템플릿을 특별히 (약간 결함이 있지만) 설계된 문제를 해결하기 위해 템플릿을 사용하지 않는 것이 좋습니다.

+0

당신이 나에게 뭔가 제안 할 수 있도록, 나는 템플릿을 피할 수 있습니까 ?? –

+0

따라서 템플릿을 피함으로써 ...이 문제를 피하십시오 ... –

+0

@sourabh : 사용하려는 모든 다른 유형 (다형성)으로 동일한 기능을 오버로드 할 수 있지만 많은 우수 사례 '규칙'에 위배됩니다. 적어도 하나는 건조한 상태입니다. –

-1

나는 몇 가지 유용한 링크를 C와 친숙하지 않다 ++하지만 여기에 있습니다 :

희망 난 당신을 돕고을!

+0

왜 아래쪽 표를 사용합니까? ?????? –

+10

@ Nathan - 아마 당신이 C++ 질문에 답을했기 때문에 대답이 무엇인지 모르고 대답으로 많이 대답했기 때문입니다. –

3

템플릿 이전에 유형에 구속받지 않는 C++ 코드는 런타임 다형성을 사용하여 작성해야했습니다. 그러나 템플릿을 사용하여 두 가지 기술을 결합 할 수 있습니다.

예를 들어 나중에 검색 할 수 있도록 모든 유형의 값을 저장한다고 가정합니다. 템플릿이 없다면, 당신은이 작업을 수행해야 할 것 :

struct PrintableThing 
{ 
    // declare abstract operations needed on the type 
    virtual void print(std::ostream &os) = 0; 

    // polymorphic base class needs virtual destructor 
    virtual ~PrintableThing() {} 
}; 

class PrintableContainer 
{ 
    PrintableThing *printableThing; 

public: 
    // various other secret stuff 

    void store(PrintableThing *p); 
}; 

이 라이브러리의 사용자가 자신의 데이터를 주위에 포장하고 그 위에 print 기능을 구현하기 위해 손으로 PrintableThing 자신의 파생 버전을 작성해야합니다.

하지만 이러한 시스템 주위에 템플릿 기반의 레이어를 포장 할 수 있습니다

template <T> 
struct PrintableType : PrintableThing 
{ 
    T instance; 

    virtual void print(std::ostream &os) 
     { os << instance; } 

    PrintableType(const T &i) 
     : instance(i) {} 
}; 

을 그리고 또한 PrintableContainer 클래스의 선언에서 헤더 라이브러리의에 메소드를 추가 :

template <class T> 
void store(const T &p) 
{ 
    store(new PrintableType(p)); 
} 

이것은 << 연산자에 컴파일시 바인딩을 사용하여 print을 구현하는 템플릿과 런타임 다형성 사이의 다리 역할을하며 복사 생성자 a lso (물론 중첩 된 인스턴스의 소멸자로 전달).

이렇게하면 라이브러리의 소스에서 숨길 수있는 구현과 함께 런타임 다형성을 기반으로 라이브러리를 작성할 수 있지만 편리하게 만들기 위해 "설탕"템플릿이 조금 추가되었습니다 용도.

문제가 있는지 여부는 필요에 따라 다릅니다. 런타임 다형성은 때로 정확히 당신이 필요로하는 것, 즉 그 자체로 순수한 기술적 이점을 가지고 있습니다. 단점이라면 컴파일러가 효과적으로 인라인 할 수있는 능력을 의심 할 여지없이 줄일 수 있습니다. 위쪽에 컴파일 시간과 이진 코드가 부풀어 오를 수 있습니다.

예제는 std::tr1::functionboost::any입니다.이 템플릿은 매우 깨끗하고 현대적인 C++ 템플릿 기반 프론트 엔드를 가지고 있지만 런타임 다형성 컨테이너로 사용됩니다.

0

템플릿의 한 가지 문제점은 컴파일 된 코드가 필요하다는 것입니다. 최종 사용자가 템플릿을 전문화/인스턴스화하는 방법을 알지 못하기 때문에 dll 파일은 가능한 모든 템플릿 전문화를 컴파일 된 형식으로 포함해야합니다. 이는 수출 쌍 < X에 Y가 > 템플릿은 무한대로 ... 쌍에게, >을 떠, 등등 < INT, 문자열 >, 쌍 < 문자열, HWND >와 쌍 < INT의 compilication을 강제해야한다는 것을 의미합니다 ..

개인용/숨김 코드의 템플릿을 제거하는 것이 더 실용적인 해결책이라고 생각합니다. 단일 템플릿 전문화 용으로 만 컴파일되는 특수 내부 함수를 작성할 수 있습니다. 다음 예제에서 internal_foo-function은 A가 int가 아닌 MyClass에서 호출되지 않습니다.

template<class A> 
class MyClass 
{ 
    int a; 
    float b; 
    A c; 

    int foo(string param1); 
    { 
    ((MyClass<int>*)this)->internal_foo(param1); 
    } 
    int internal_foo(string param1); // only called on MyClass<int> instances 
}; 

template<> 
__declspec(dllexport) int MyClass<int>::internal_foo(string param1) 
{ 
    ... secret code ... 
} 

물론 이것은 해킹입니다. 이 변수를 사용할 때 멤버 변수 "c"를 사용하지 않도록주의해야합니다. 왜냐하면 internal_foo가 정수라고 생각하기 때문에 항상 정수가 아니기 때문입니다. 그리고 단언 할 때 자신을 지킬 수도조차 없습니다. C++은 발에서 몸을 쏠 수있게 해주 며, 너무 늦을 때까지 그것에 대한 징후를주지 않습니다.

추신. 이 코드를 테스트하지 않았으므로 약간의 미세 조정이 필요합니다. 컴파일러가 dll 파일에서 internal_foo 함수를 찾기 위해 __declspec (dllimport)가 필요한지 확실하지 않은 경우 ...

1

나는 당신을 위해 몇 가지 뉴스를 가지고 있습니다. export을 사용해도 템플릿 코드를 모두 해제해야합니다. export은 헤더 파일에 정의를 넣을 필요가 없도록 만듭니다. 너는 완전히 붙어있다. 사용할 수있는 유일한 기술은 템플릿이 아닌 일부 기능을 분리하여 다른 클래스에 넣는 것입니다. 그러나보기가 좋지 않으며 일반적으로 void* 및 게재 위치 newdelete이 포함됩니다. 그것은 짐승의 본질 일뿐입니다.

+0

"일반적으로 void * 및 placement new와 delete가 포함됩니다. 그럴 필요가 없습니다. –

0

템플릿을 사용하면 코드가 전달되는 것을 피할 수 없습니다 (코드가 고정 된 유형 집합에서만 작동하지 않는 경우 명시 적으로 인스턴스화 할 수 있음). 내가 일하는 곳에서는 POD 유형 (CORBA/DDS/HLA 데이터 정의)에서 작동해야하는 라이브러리가 있으므로 최종적으로 템플릿을 제공합니다.

템플릿은 대부분의 코드를 바이너리 형식으로 제공되는 템플릿이 아닌 코드에 위임합니다. 경우에 따라 템플릿에 전달 된 유형으로 작업을 직접 수행해야하므로 템플리트가 적용되지 않은 코드에 위임 할 수 없으므로 완벽한 솔루션은 아니지만 CEO를 만들기에 충분한 코드 부분을 숨 깁니다 행복한 (프로젝트 책임자는 기꺼이 템플릿의 모든 코드를 제공합니다).

Neil이 질문에 대한 의견에서 지적한 것처럼 대다수의 경우 Neil은 다른 사람들이 다시 쓸 수없는 코드에는 마법 같은 것이 없습니다.

+0

더 자세히 설명해 주실 수 있습니다. –