如何使用type_traits或模板函数专门化来合并模板方法

时间:2014-05-30 23:50:02

标签: c++ templates template-specialization typetraits specialization

我正在尝试从类似于下面所示类的类中合并一些非常相似的函数方法,并且我认为有效实现它的最佳方法是通过使用模板结合模板函数专门化或者替代类型特征。我是模板专业化和类型特征的新手,但我理解基本概念,这就是为什么我要求对细节提供一些指导。无论如何,作为一个起点,我的类是一个智能缓冲类,它有许多类似于下面列出的方法签名。

class OldSafeBuffer {
public:
    intmax_t writeAt(const intmax_t& rIndex, const uint32_t val32);
    intmax_t writeAt(const intmax_t& rIndex, const int32_t val32);
    intmax_t readFrom(const intmax_t& rIndex, uint32_t& rVal32);
    intmax_t readFrom(const intmax_t& rIndex, int32_t& rVal32);
    intmax_t writeAt(const intmax_t& rIndex, const uint16_t val16);
    intmax_t writeAt(const intmax_t& rIndex, const int16_t val16);
    intmax_t readFrom(const intmax_t& rIndex, uint16_t& rVal16);
    intmax_t readFrom(const intmax_t& rIndex, int16_t& rVal16);
    intmax_t read(uint32_t& rVal32);
    intmax_t read(int32_t& rVal32);
    intmax_t read(uint16_t& rVal16);
    intmax_t read(int16_t& rVal16);
protected:
    // Actual memory storage.
    std::unique_ptr<char[]> mBuffer;
    // Buffer length
    intmax_t mBufferLength;
    // Represents the largest byte offset referenced.
    // Can be used to retrieve written length of buffer.
    intmax_t mHighWaterMark;
    // If set, caller wanted to pack data in network-byte-order.
    bool mPackNBO;
    // Set on construction, determines whether value needs to be byte-swapped.
    bool mSwapNeeded;
    // Used for file compatibility
    intmax_t mPosition;
};

我认为这将是转换为使用模板函数的完美候选者,因为这些函数非常相似,并且我在每个方法中都有很多重复的代码。方法之间的区别主要是符号和16或32位值参数的大小。

无论如何要整合readFrom方法,我将以下方法放在一起。我也为写方法做了类似的事情。这些内容显示在编译live example

/**
 * Read value (signed or unsigned) from buffer at given byte offset.
 *
 * @param rIndex [in]
 * @param rVal   [out]
 *
 * @return BytesRead or -1 on error
 */
template <typename T>
inline intmax_t readFrom(const intmax_t& rIndex, T& rVal)
{
    if ((rIndex + static_cast<intmax_t>(sizeof(T))) <= mBufferLength) {
        T* pVal = (T *)&mBuffer[rIndex];
        rVal = *pVal;
        // @JC Partial Template Specialization for 16 bit entities?
        if (sizeof(rVal) > sizeof(int16_t)) {
            SWAP32(rVal);
        } else {
            SWAP16(rVal);
        }
        mPosition = rIndex + sizeof(T);
        return sizeof(rVal);
    }
    return -1;
}

从我的评论中可以看出,我仍然需要知道'T&amp; rVal'参数,以决定是否对参数执行SWAP32或SWAP16。这就是为什么我认为type_traits可能有用而不必进行运行时检查以比较参数的大小。

我认为我在正确的轨道上,但我无法弄清楚如何使用type_traits检查并根据参数类型执行某些操作。我认为,或者我可以使用模板方法专门化来对16位参数进行特殊处理,但我认为这不会节省太多精力,因为我还必须专注于16位参数类型的带符号adn无符号变体(假设非专用版本用于32位值参数)。任何帮助解决这个问题将非常感激。

3 个答案:

答案 0 :(得分:1)

您可以使用以下内容:

template<typename T, std::size_t N = sizeof(T)> struct Swap;

template<typename T> struct Swap<T, 1> {
    void operator() (T&) const { /* Do nothing*/ }
};

template<typename T> struct Swap<T, 2> {
    void operator() (T& val) const { SWAP16(val); }
};

template<typename T> struct Swap<T, 4> {
    void operator() (T& val) const { SWAP32(val); }
};

然后叫它:

Swap<T>()(rVal);

所以在上下文中:

if (sizeof(T) > sizeof(int16_t)) {
    SWAP32(val);
} else {
    SWAP16(val);
}

可以写成

Swap<T>()(val);

答案 1 :(得分:0)

您可以使用模板专精来执行专门的swap函数,如下例所示:

template<typename T>
struct Swap;

template<>
struct Swap<int16_t> {
  static void swap(int16_t val) { SWAP16(val); }
};

template<>
struct Swap<int32_t> {
  static void swap(int32_t val) { SWAP32(val); }
};

然后你可以在你的代码中调用它:

template <typename T>
inline intmax_t readFrom(const intmax_t& rIndex, T& rVal)
{
    if ((rIndex + static_cast<intmax_t>(sizeof(T))) <= mBufferLength) {
        T* pVal = (T *)&mBuffer[rIndex];
        rVal = *pVal;
        Swap<T>::swap(rVal);
        mPosition = rIndex + sizeof(T);
        return sizeof(rVal);
    }
    return -1;
}

答案 2 :(得分:0)

您可以为4种类型定义交换方法:

inline void swap_endianess(int16_t& value) { SWAP16(value); }
inline void swap_endianess(uint16_t& value) { SWAP16(value); }
inline void swap_endianess(int32_t& value) { SWAP32(value); }
inline void swap_endianess(uint32_t& value) { SWAP32(value); }

让模板函数调度到正确的函数。

所以而不是

if (sizeof(T) > sizeof(int16_t)) {
    SWAP32(val);
} else {
    SWAP16(val);
}

只需致电

swap_endianess(val);