根据sizeof类型的模板特化

时间:2010-08-20 08:23:12

标签: c++ templates

我想提供一个模板化函数,根据模板类型的大小改变其实现( - > specialization)。

与此类似的东西(省略了类型转换),但没有if / 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 ...

我不得不承认,我现在被困住了,所以我感谢你的帮助或建议

4 个答案:

答案 0 :(得分:20)

您不需要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); }

答案 1 :(得分: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 :(得分:3)

仅仅是为了展示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成员的类型,这是一个布尔值。

答案 3 :(得分: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;
}