2010-08-20 4 views
16

템플릿 유형의 크기에 따라 구현 (-> 전문화)이 달라지는 템플릿 기능을 제공하고 싶습니다.sizeof 유형에 따른 템플릿 전문

이 (생략 타입 변환)과 비슷한,하지만없는 경우/ELSEIF :

template<class T> 
T byteswap(T & swapIt) 
{ 
    if(sizeof(T) == 2) 
    { 
     return _byteswap_ushort (swapIt); 
    } 
    else if(sizeof(T) == 4) 
    { 
     return _byteswap_ulong(swapIt); 
    } 
    else if(sizeof(T) == 8) 
    { 
     return _byteswap_uint64(swapIt); 
    } 
      throw std::exception(); 
} 

내 목표에 도달하기 위해 많은 도로가 알고 있지만 내가 시도 이후에 대한 SFINAEtype traits 내가 '배우 특히 컴파일 타임에 이러한 기술을 사용하여 선택할 전문 분야와 어떤 호출이 인정되지 않는지에 관심이 있습니다.

아마도 내가 인정해야

, 나는 지금 붙어있어, 내가 어떤 도움이나 조언

답변

17

당신 돈 주셔서 감사합니다 ... 클래스 특성 is_4ByteLong을 구현하고 부스트 :: enable_if를 사용하여 SFINAE가 필요하거나 형질을 입력해야합니다. 바닐라 템플릿 전문화로 충분합니다. 물론 C++ (98)은 함수 템플릿 부분 특수화를 지원하지 않으므로 구조체에 대한 특수화가 필요합니다.

template <typename T, size_t n> 
struct ByteswapImpl 
/* 
{ 
    T operator()(T& swapIt) const { throw std::exception(); } 
} 
*/ // remove the comments if you need run-time error instead of compile-time error. 
; 

template <typename T> 
struct ByteswapImpl<T, 2> { 
    T operator()(T& swapIt) const { return _byteswap_ushort (swapIt); } 
}; 

// ... 

template <typename T> 
T byteswap(T& swapIt) { return ByteswapImpl<T, sizeof(T)>()(swapIt); } 
+5

좋은 답변이지만 'ByteswapImpl'의 기본 구현을 만들지는 않습니다. 그렇게하면 필요한 전문화가 존재하지 않으면 컴파일 오류가 발생합니다. – Job

+1

그리고이 함수는 정적 일 수 있으므로 (boost :: numeric_cast' 및'boost :: numeric_conververt'와 비슷한) 객체를 생성 할 필요가 없습니다. – Philipp

+0

필자는 기능 템플릿 * 부분 * 전문화 만 지원되지 않는다는 인상하에있었습니다 ... 제가 틀렸습니까? – Job

4

는 단순히 템플릿 인수로 크기를 취하는 보조 클래스를 만들 :

template <class T> 
typename boost::enable_if_c< sizeof(T) == 2, T >::type 
swapIt(T& rhs) { return _byteswap_short(rhs); } 

template <class T> 
typename boost::enable_if_c< sizeof(T) == 4, T >::type 
swapIt(T& rhs) { return _byteswap_long(rhs); } 
: 당신이 그것에 대해 이야기하기 때문에 그냥 행동 enable_if을 보여주는를 위해서
#include <cstddef> 
#include <iostream> 


template<std::size_t Size> 
struct ByteSwapper { }; 

template<> 
struct ByteSwapper<2> { 
    static unsigned short swap(unsigned short a) { 
    return 2 * a; 
    } 
}; 

template<typename T> 
T byteswap(const T& a) { 
    return ByteSwapper<sizeof(T)>::swap(a); 
} 


int main() { 
    unsigned short s = 5; 
    std::cout << byteswap(s) << std::endl; 
    unsigned int i = 7; 
    // std::cout << byteswap(i) << std::endl; // error 
} 
2

,

등 ...

물론 던지기 대신에 유형이 요구 사항 중 하나를 충족시키지 않아 컴파일 타임 오류가 발생하면 구현하십시오.

두 노트 : typename::type

  • 사용 enable_if 부울입니다 ::value 멤버가 포함 된 형식을 필요로하는 반면 내 표현이 직접 부울 값으로 평가하기 때문에 내가 enable_if_c을 사용
  • 필수입니다.
1

나는 다음과 같은 방법을 제안 할 수 있습니다 그것의 장점은 피연산자가 유효한 크기가 아닌 경우는 throw에 예외가 없다는 것입니다. 그냥 연결되지 않습니다. 그래서 당신은 빌드 타임에 오류 검사를했습니다.

template<int size> 
void byteswapInPlace(void* p); 

template<> void byteswapInPlace<1>(void* p) { /* do nothing */ } 

template<> void byteswapInPlace<2>(void* p) 
{ 
    _byteswap_ushort((ushort*) p); 
} 

template<> void byteswapInPlace<4>(void* p) 
{ 
    _byteswap_ulong((ulong*) p); 
} 

template<> void byteswapInPlace<8>(void* p) 
{ 
    _byteswap_uint64((uint64*) p); 
} 


template<class T> 
T byteswap(T & swapIt) 
{ 
    byteswapInPlace<sizeof(T)>(&swapIt); 
    return swapIt; 
} 
+2

대신에 일종의 정적 어설 션을 넣을 수 있습니다 (예 :g BOOST_STATIC_ASSERT')를 기본 경우에 사용합니다. 연결될 때까지 기다릴 필요가 없습니다. – UncleBens

+0

예, 맞습니다. 이것이 제가 할 일입니다 : 컴파일러 오류를 생성하는 기본 imlpementation. – valdo