2010-08-20 71 views
16

我想提供一个模板化函数,根据模板类型的大小来改变它的实现( - > specialization)。根据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我我特别感兴趣的是使用这些技术的解决方案,以便在编译时决定选择哪种专业化以及哪些呼叫不被接纳。

或许实现一类特征is_4ByteLong和使用boost :: enable_if ...

我不得不承认,我卡住了,现在,所以我感谢你对任何帮助或建议

回答

17

你不不需要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 2010-08-20 08:41:50

+1

该函数可以是静态的,因此不需要创建对象(类似于boost :: numeric_cast和boost :: numeric_conververt)。 – Philipp 2010-08-20 08:44:32

+0

我的印象是只有函数模板* partial * specialization不被支持......我错了吗? – Job 2010-08-20 09:04:26

4

简单地使一个辅助类,它的大小与一个模板参数:

#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

只是为了表明其行动enable_if的缘故,因为你谈到的:

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); } 

等...

当然,不是扔,而是没有如果该类型不符合任何要求并因此发生编译时错误,则执行。

两个附注:

  • 使用typename::type是强制性
  • 我用enable_if_c因为我的表达式的计算结果为布尔值直接,而enable_if需要含有一个::value构件,其是布尔类型。
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 2010-08-20 09:39:11

+0

是的,你是对的,这是我会做的:默认imlpementation它会产生一个编译器错误。 – valdo 2010-08-20 14:10:13