문제

내 직장에서 우리는 사용하는 경향이 있습니다 ioStream, , 벡터, 지도, 그리고 이상한 연산 또는 두 개. 우리는 실제로 템플릿 기술이 문제에 대한 최상의 솔루션 인 많은 상황을 발견하지 못했습니다.

내가 여기서 찾고있는 것은 아이디어와 선택적으로 템플릿 기술을 사용하여 실생활에서 직면 한 문제에 대한 새로운 솔루션을 만드는 방법을 보여주는 샘플 코드입니다.

뇌물로서, 당신의 답변에 대한 투표를 기대하십시오.

도움이 되었습니까?

해결책

나는 주로 부스트와 STL에서 많은 템플릿 코드를 사용했지만 거의 필요하지 않았습니다. 쓰다 어느.

몇 년 전 예외 중 하나는 Windows PE-Format EXE 파일을 조작하는 프로그램에있었습니다. 회사는 64 비트 지원을 추가하기를 원했지만 ExeFile 파일을 처리하기 위해 작성한 클래스는 파일을 32 비트에서만 작동 시켰습니다. 64 비트 버전을 조작하는 데 필요한 코드는 본질적으로 동일했지만 다른 주소 유형 (32 비트 대신 64 비트)을 사용해야했기 때문에 두 개의 다른 데이터 구조가 다릅니다.

STL의 단일 템플릿을 사용하여 std::string 그리고 std::wstring, 나는 만들기로 결정했다 ExeFile 데이터 구조가 다르고 주소 유형이 매개 변수로 템플릿입니다. 내가 아직도 사용해야했던 곳이 두 곳이있었습니다. #ifdef WIN64 라인 (약간 다른 처리 요구 사항)이지만 실제로는 어렵지 않았습니다. 우리는 현재 해당 프로그램에서 전체 32 및 64 비트 지원을 받았으며 템플릿을 사용한다는 것은 두 버전 모두에 자동으로 적용된 이후로 수행 한 모든 수정을 의미합니다.

다른 팁

템플릿에 대한 일반 정보 :

템플릿은 동일한 코드를 사용해야하지만 컴파일 시간에 유형이 알려진 다른 데이터 유형에서 작동 할 때마다 유용합니다. 또한 어떤 종류의 컨테이너 객체가있을 때.

매우 일반적인 사용법은 거의 모든 유형의 데이터 구조에 대한 것입니다. 예를 들어 : 단일 링크 된 목록, 이중 링크 된 목록, 나무, 트리, 해시 타이블, ...

또 다른 매우 일반적인 사용법은 알고리즘을 정렬하는 것입니다.

템플릿 사용의 주요 장점 중 하나는 코드 복제를 제거 할 수 있다는 것입니다. 코드 복제는 프로그래밍시 피해야 할 가장 큰 것 중 하나입니다.

매크로 또는 템플릿으로 함수 max를 구현할 수 있지만 템플릿 구현은 안전하고 더 나은 유형입니다.

그리고 이제 멋진 것들에 :

또한 참조하십시오 템플릿 메타 프로 그램, 이는 런타임이 아닌 컴파일 타임에서 코드를 사전 평가하는 방법입니다. 템플릿 Metaprogramming에는 불변 변수 만 있으므로 변수가 변경 될 수 없습니다. 이 템플릿으로 인해 메타 프로 그램은 기능적 프로그래밍 유형으로 볼 수 있습니다.

Wikipedia의 템플릿 메타 프로 그램 의이 예를 확인하십시오. 템플릿을 사용하는 방법을 보여줍니다 컴파일 시간에 코드를 실행하십시오. 따라서 런타임에 사전 계산 된 상수가 있습니다.

template <int N>
struct Factorial 
{
    enum { value = N * Factorial<N - 1>::value };
};

template <>
struct Factorial<0> 
{
    enum { value = 1 };
};

// Factorial<4>::value == 24
// Factorial<0>::value == 1
void foo()
{
    int x = Factorial<4>::value; // == 24
    int y = Factorial<0>::value; // == 1
}

템플릿을 사용하여 고유 한 코드를 만드는 장소는 현대 C ++ 디자인에서 Andrei Alexandrescu가 설명한대로 정책 클래스를 구현하는 것입니다. 현재 Bea H H H Oracle의 Tuxedo TP 모니터와 상호 작용하는 클래스 세트가 포함 된 프로젝트를 진행하고 있습니다.

Tuxedo가 제공하는 시설 중 하나는 트랜잭션 영구 대기열이므로 대기열과 상호 작용하는 클래스 TPQUE가 있습니다.

class TpQueue {
public:
   void enqueue(...)
   void dequeue(...)
   ...
}

그러나 대기열이 트랜잭션이므로 원하는 거래 동작을 결정해야합니다. 이것은 tpqueue 클래스 밖에서별로 이루어질 수 있지만 각 tpqueue 인스턴스에 트랜잭션에 대한 자체 정책이있는 경우 더 명확하고 오류가 적습니다. 따라서 다음과 같은 트랜잭션 정책 클래스 세트가 있습니다.

class OwnTransaction {
public:
   begin(...)  // Suspend any open transaction and start a new one
   commit(..)  // Commit my transaction and resume any suspended one
   abort(...)
}

class SharedTransaction {
public:
   begin(...)  // Join the currently active transaction or start a new one if there isn't one
   ...
}

그리고 tpqueue 클래스는 다시 작성됩니다

template <typename TXNPOLICY = SharedTransaction>
class TpQueue : public TXNPOLICY {
   ...
}

따라서 tpqueue 내부에 필요에 따라 시작 (), abort (), commit ()를 호출 할 수 있지만 인스턴스를 선언하는 방식에 따라 동작을 변경할 수 있습니다.

TpQueue<SharedTransaction> queue1 ;
TpQueue<OwnTransaction> queue2 ;

나는 템플릿 (boost.fusion의 도움으로)을 사용하여 개발중인 하이퍼 그래프 라이브러리를위한 유형 안전 정수를 달성했습니다. 나는 (하이퍼) 엣지 ID와 정점 ID가 모두 정수입니다. 템플릿을 사용하면 정점 및 하이퍼 러쉬 ID가 다른 유형이되었으며 다른 하나가 컴파일 타임 오류가 발생할 때 다른 유형을 사용하여 사용됩니다. 런타임 디버깅으로 가질 수있는 두통을 많이 절약했습니다.

실제 프로젝트의 한 예는 다음과 같습니다. 다음과 같은 getter 기능이 있습니다.

bool getValue(wxString key, wxString& value);
bool getValue(wxString key, int& value);
bool getValue(wxString key, double& value);
bool getValue(wxString key, bool& value);
bool getValue(wxString key, StorageGranularity& value);
bool getValue(wxString key, std::vector<wxString>& value);

그런 다음 '기본값'값을 가진 변형입니다. 키가 존재하는 경우 키의 값을 반환하거나 그렇지 않은 경우 기본값을 반환합니다. 템플릿으로 인해 6 개의 새로운 기능을 직접 만들지 않아도되었습니다.

template <typename T>
T get(wxString key, const T& defaultValue)
{
    T temp;
    if (getValue(key, temp))
        return temp;
    else
        return defaultValue;
}

규제 소비하는 템플릿은 수많은 컨테이너 클래스, 스마트 포인터 부스트, 스코프 가드, 몇 가지 STL 알고리즘.

템플릿을 작성한 시나리오 :

  • 맞춤형 컨테이너
  • 메모리 관리, 유형 안전 및 CTOR/DTOR 구현 공간 위에 * 할당 기
  • 오버로드에 대한 일반적인 구현은 다른 유형 (예 :)

    bool은 innan (float *, int) bool을 포함합니다 (double *, int)

둘 다 (로컬, 숨겨진) 도우미 기능을 호출합니다.

template <typename T>
bool ContainsNanT<T>(T * values, int len) { ... actual code goes here } ;

유형이 특정 속성을 갖는 한 유형과 무관 한 특정 알고리즘 (예 : 이진 직렬화).

template <typename T>
void BinStream::Serialize(T & value) { ... }

// to make a type serializable, you need to implement
void SerializeElement(BinStream & strean, Foo & element);
void DeserializeElement(BinStream & stream, Foo & element)

가상 함수와 달리 템플릿은 더 많은 최적화를 허용합니다.


일반적으로 템플릿을 사용하면 다양한 유형에 대한 하나의 개념 또는 알고리즘을 구현할 수 있으며 컴파일 시간에 이미 차이가 해결됩니다.

우리는 COM을 사용하고 직접 또는 다른 인터페이스를 구현할 수있는 객체에 대한 포인터를 수락합니다.IServiceProvider](http://msdn.microsoft.com/en-us/library/cc678965(vs.85).aspx) 이로 인해이 도우미 캐스트와 같은 기능을 만들어 냈습니다.

// Get interface either via QueryInterface of via QueryService
template <class IFace>
CComPtr<IFace> GetIFace(IUnknown* unk)
{
    CComQIPtr<IFace> ret = unk; // Try QueryInterface
    if (ret == NULL) { // Fallback to QueryService
        if(CComQIPtr<IServiceProvider> ser = unk)
            ser->QueryService(__uuidof(IFace), __uuidof(IFace), (void**)&ret);
    }
    return ret;
}

템플릿을 사용하여 기능 객체 유형을 지정합니다. 나는 종종 함수 객체를 인수 (통합 함수, 최적화 함수 등)로 취하는 코드를 작성하며 상속보다 템플릿이 더 편리하다고 생각합니다. 따라서 통합기 또는 최적화기와 같은 기능 객체를 수신하는 코드에는 작동하는 기능 객체의 종류를 지정하는 템플릿 매개 변수가 있습니다.

명백한 이유 (다른 데이터 유형에서 작동하여 코드-복제 방지와 같은)는 정책 기반 설계라고하는이 멋진 패턴이 있습니다. 나는 질문을했다 정책 대 전략.

자,이 기능에 대해 그다지 멋진 점은 무엇입니까? 다른 사람들이 사용할 인터페이스를 작성한다고 생각하십시오. 인터페이스는 자체 도메인의 모듈이기 때문에 인터페이스가 사용될 것임을 알고 있습니다. 그러나 당신은 사람들이 그것을 어떻게 사용할 것인지 아직 모릅니다. 정책 기반 설계는 향후 재사용을위한 코드를 강화합니다. 특정 구현이 의존하는 데이터 유형과 무관하게 만듭니다. 코드는 단지 "slurped"입니다. :-)

특성은 그 자체로 훌륭한 아이디어입니다. 특정 동작, 데이터 및 TypEdata를 모델에 첨부 할 수 있습니다. 특성은이 세 필드 모두의 완전한 매개 변수화를 허용합니다. 그리고 최고, 그것은 코드를 재사용 할 수있는 아주 좋은 방법입니다.

한 번은 다음 코드를 보았습니다.

void doSomethingGeneric1(SomeClass * c, SomeClass & d)
{
   // three lines of code
   callFunctionGeneric1(c) ;
   // three lines of code
}

10 번 반복 :

void doSomethingGeneric2(SomeClass * c, SomeClass & d)
void doSomethingGeneric3(SomeClass * c, SomeClass & d)
void doSomethingGeneric4(SomeClass * c, SomeClass & d)
// Etc

각 함수는 동일한 6 줄의 코드 복사/붙여 넣기를 갖고 매번 동일한 숫자 접미사로 다른 함수 CallFunctionGenericx를 호출합니다.

모든 것을 완전히 리팩터링 할 방법이 없었습니다. 그래서 나는 리팩토링을 현지로 유지했습니다.

이 방법으로 코드를 변경했습니다 (메모리에서) :

template<typename T>
void doSomethingGenericAnything(SomeClass * c, SomeClass & d, T t)
{
   // three lines of code
   t(c) ;
   // three lines of code
}

기존 코드를 다음과 같이 수정했습니다.

void doSomethingGeneric1(SomeClass * c, SomeClass & d)
{
   doSomethingGenericAnything(c, d, callFunctionGeneric1) ;
}

void doSomethingGeneric2(SomeClass * c, SomeClass & d)
{
   doSomethingGenericAnything(c, d, callFunctionGeneric2) ;
}

등.

이것은 템플릿을 다소 차지하는 것이지만 결국에는 typedefed 함수 포인터를 사용하거나 매크로를 사용하는 것보다 낫다고 생각합니다.

나는 개인적으로 호기심이 많은 템플릿 패턴을 일부 형태의 하향식 디자인과 상향식 구현을 시행하는 수단으로 사용했습니다. 예를 들어 양식 및 인터페이스의 특정 요구 사항이 컴파일 시간에 파생 된 유형에서 시행되는 일반 핸들러에 대한 사양입니다. 다음과 같이 보입니다.

template <class Derived>
struct handler_base : Derived {
  void pre_call() {
    // do any universal pre_call handling here
    static_cast<Derived *>(this)->pre_call();
  };

  void post_call(typename Derived::result_type & result) {
    static_cast<Derived *>(this)->post_call(result);
    // do any universal post_call handling here
  };

  typename Derived::result_type
  operator() (typename Derived::arg_pack const & args) {
    pre_call();
    typename Derived::result_type temp = static_cast<Derived *>(this)->eval(args);
    post_call(temp);
    return temp;
  };

};

그런 다음이 핸들러 가이 템플릿에서 파생되고 하향식 디자인을 시행 한 다음 상향식 사용자 정의를 허용하는 데 사용될 수 있습니다.

struct my_handler : handler_base<my_handler> {
  typedef int result_type; // required to compile
  typedef tuple<int, int> arg_pack; // required to compile
  void pre_call(); // required to compile
  void post_call(int &); // required to compile
  int eval(arg_pack const &); // required to compile
};

이를 통해 handler_base <> 파생 된 유형 만 다루는 일반적인 다형성 기능을 가질 수 있습니다.

template <class T, class Arg0, class Arg1>
typename T::result_type
invoke(handler_base<T> & handler, Arg0 const & arg0, Arg1 const & arg1) {
  return handler(make_tuple(arg0, arg1));
};

템플릿을 정책 클래스로 사용할 수 있다고 이미 언급되었습니다. 뭔가를하십시오. 나는 이것을 많이 사용한다.

나는 또한 부동산지도의 도움으로 그것들을 사용합니다 (이에 대한 자세한 내용은 Boost 사이트를 참조하십시오), 일반적인 방식으로 데이터에 액세스하기 위해. 이를 통해 데이터를 검색하는 방식을 변경하지 않고도 저장 방식을 변경할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top