如何使用const / nonconst指针/引用参数模板化函数

时间:2017-07-01 13:33:02

标签: c++ c++11 c++14 c++17

假设我有以下一组功能:

typedef uint8_t byte;

inline byte *as_bytes(char *data) {
    return reinterpret_cast<byte*>(data);
}

inline byte *as_bytes(std::vector<byte> &v) {
    return &v[0];
}

inline byte *as_bytes(QByteArray &a) {
    return as_bytes(a.data());
}

inline const byte *as_cbytes(const char *data) {
    return reinterpret_cast<const byte*>(data);
}

inline const byte *as_cbytes(const std::vector<byte> &v) {
    return &v[0];
}

inline const byte *as_cbytes(const QByteArray &a) {
    return as_cbytes(a.data());
}

问题:我可以模拟这些函数,以便constness和指针/引用类型推导能够正常工作吗?我希望看到的结果可能如下:

template<typename T>
inline byte *as_bytes(T data) {
    return reinterpret_cast<byte*>(data);
}

template<>
inline byte *as_bytes(std::vector<byte> &v) {
    return &v[0];
}

template<>
inline byte *as_bytes(QByteArray &a) {
    return as_bytes(a.data());
}

但当然这个代码对我来说不起作用有两个原因:

  • 我希望推导出constness of argument并将其转发给返回类型;
  • 由于我们讨论的是函数,std::vectorQByteArray的特化将无法按预期工作,因为由于函数过载,将始终选择template<typename T> inline byte *as_bytes(T data)

也许有一些C ++ 11/14/17机制可以解决这些问题并最终得到3个漂亮的函数?

1 个答案:

答案 0 :(得分:2)

这可能适合您的需要:

template<typename T>
inline auto as_bytes(T *data) {
    return reinterpret_cast<
        typename std::conditional<std::is_const<T>{}, const byte*, byte*>::type
    >(data);
}

template <typename T>
inline auto as_bytes(T &t) -> decltype(as_bytes(t.data())) {
    return as_bytes(t.data());
}

这是如何运作的:

  • 第一个模板函数需要T*,以便对std::vector / QByteArray(或您可以添加的任何其他类型)的(const)引用永远不会匹配此模板,并使用Tstd::conditional的组合从std::is_const推导出常量。

  • 第二个模板函数将匹配具有成员函数T的任何类型data()std::vector的情况(自C ++ 11以来)和{{ 1}}),并推导出constness,因为QByteArray有一个const重载。

在第二个函数中使用尾随返回类型将允许您为不提供T::data方法的类型添加额外的重载,而不会产生歧义。