【问题标题】:template specialization according to sizeof type根据 sizeof 类型的模板专业化
【发布时间】:2010-08-20 08:23:12
【问题描述】:

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

类似的东西(省略类型转换),但没有 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();
}

我知道有很多途径可以实现我的目标,但由于我尝试了解 SFINAE 和 type traits不被录取。

也许实现一个类特征 is_4ByteLong 并使用 boost::enable_if...

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

【问题讨论】:

    标签: c++ templates


    【解决方案1】:

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

    【讨论】:

    • 不错的答案,但我不会默认实现ByteswapImpl。这样,如果所需的特化不存在,你只会得到一个编译错误。
    • 并且函数可以是静态的,因此不必创建对象(类似于boost::numeric_cast 和boost::numeric_conververt)。
    • 我的印象是只支持函数模板部分特化......我错了吗?
    • @Job:你是对的,但由于T 在这里没有精确说明,我们实际上是在谈论部分专业化。
    • @Job:谢谢,加回“部分”。
    【解决方案2】:

    只需制作一个以大小为模板参数的辅助类:

    #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
    }
    

    【讨论】:

      【解决方案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 成员的类型,它是一个布尔值。

      【讨论】:

        【解决方案4】:

        我可以提出以下方法: 它的好处是如果操作数不是有效的大小,您不必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;
        }
        

        【讨论】:

        • 您可以在基本情况下放置某种静态断言(例如BOOST_STATIC_ASSERT)。无需等到链接出错。
        • 是的,你是对的,这就是我要做的:默认实现会产生编译器错误。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-18
        • 1970-01-01
        相关资源
        最近更新 更多