【问题标题】:How can I specialize a C++ template for a range of integer values?如何为一系列整数值专门化 C++ 模板?
【发布时间】:2012-06-13 16:24:56
【问题描述】:

有没有一种方法可以让模板专业化基于一系列值而不仅仅是一个值?我知道以下代码不是有效的 C++ 代码,但它显示了我想做的事情。我正在为 8 位机器编写代码,因此使用 int 和 chars 的速度存在差异。

template<unsigned SIZE>
class circular_buffer {
   unsigned char buffer[SIZE];
   unsigned int head; // index
   unsigned int tail; // index
};

template<unsigned SIZE <= 256>
class circular_buffer {
   unsigned char buffer[SIZE];
   unsigned char head; // index
   unsigned char tail; // index
};

【问题讨论】:

    标签: c++ templates


    【解决方案1】:

    试试std::conditional:

    #include <type_traits>
    
    template<unsigned SIZE>
    class circular_buffer {
    
        typedef typename
            std::conditional< SIZE < 256,
                              unsigned char,
                              unsigned int
                            >::type
            index_type;
    
        unsigned char buffer[SIZE];
        index_type head;
        index_type tail;
    };
    

    如果您的编译器尚不支持 C++11 的这一部分,boost libraries. 中提供了等价物

    再说一次,自己动手很容易(归功于 KerrekSB):​​

    template <bool, typename T, typename F>
    struct conditional {
        typedef T type;
    };
    
    template <typename T, typename F>  // partial specialization on first argument
    struct conditional<false, T, F> {
        typedef F type;
    }; 
    

    【讨论】:

    • 不得不说,这很有用。
    • std::conditional 这样的特征对自己来说是微不足道的,所以如果你没有它,你真的不需要任何库:template &lt;bool, typename T, typename&gt; struct conditional { typedef T type; }; template &lt;typename T, typename U&gt; struct conditional&lt;false, T, U&gt; { typedef U type; };
    • 干杯@KerrekSB,我将其添加到答案中。
    【解决方案2】:

    使用额外的默认bool 参数:

    // primary template handles false
    template<unsigned SIZE, bool IsSmall = SIZE <= 256>
    class circular_buffer {
       unsigned char buffer[SIZE];
       unsigned int head; // index
       unsigned int tail; // index
    };
    
    // specialization for true
    template<unsigned SIZE>
    class circular_buffer<SIZE, true> {
       unsigned char buffer[SIZE];
       unsigned char head; // index
       unsigned char tail; // index
    };
    

    【讨论】:

    • 如果 IsSmall = SIZE &lt;= 256 在某处有括号我会更高兴
    • @MooingDuck 喜欢这样吗? IsSmall = (SIZE &lt;= 256)
    • @MooingDuck 不需要。 &lt; 默认小于。这就是为什么有template 消歧器的原因。令人困惑的是 &gt; 默认情况下是关闭模板,您需要括号。 C++ 很棒,不是吗?
    • @R.MartinhoFernandes:如果是需要,我会编辑这个问题。我只是说我会更快乐。不过你仍然得到了 +1。
    【解决方案3】:

    另一个可能的选择:

    template <unsigned SIZE>
    struct offset_size {
        typedef typename offset_size<SIZE - 1>::type type;
    };
    
    template <>
    struct offset_size<0> {
        typedef unsigned char type;
    };
    
    template <>
    struct offset_size<257> {
        typedef unsigned int type;
    };
    
    template<unsigned SIZE>
    class circular_buffer {
       unsigned char buffer[SIZE];
       typename offset_size<SIZE>::type head; // index
       typename offset_size<SIZE>::type tail; // index
    };
    

    (Ideone example)

    【讨论】:

    • 你真是个虐待狂,这太残忍了。编译器。尝试编译offset_size&lt;MAX_INT&gt;,编译器要实例化数十亿个模板类!
    • 确实,如果您不小心使用此技术,您将触发error: template instantiation depth exceeds maximum of ___(gcc 上默认为 500)。
    【解决方案4】:

    我讨厌处理类型的混乱程度,因此我提出了一些更简单的方法,利用constexpr。当不需要变化类型时,此变体允许不同的行为,并解决了适合范围而不只是值的一侧的需要:

    template<bool> struct If;
    
    constexpr bool InClosedRange(std::size_t Value, std::size_t Lower, std::size_t Upper)
    {
        return (Lower <= Value) && (Value <= Upper);
    }
    
    // Usage:
    template<size_t Width, If<true>>
    class Foo;
    
    template<size_t Width, If<InClosedRange(Width, 1, 41)>>
    class Foo { /* ... */ };
    
    template<size_t Width, If<InClosedRange(Width, 42, 142)>>
    class Foo { /* ... */ };
    

    灵感来自:https://stackoverflow.com/a/9516959/929315

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多