【问题标题】:Specialized templates for pointer and c-style array variables指针和 c 样式数组变量的专用模板
【发布时间】:2019-04-11 15:23:02
【问题描述】:

当我在启用 C++11 的情况下编译代码时,我有以下代码有效。是否也可以编写专门化以使其与 C++98 编译器一起使用?

#include <iostream>
#include <type_traits>
#include <cstdint>

template<typename T, typename std::enable_if_t<!std::is_pointer<T>::value, int> = 0>
void CheckSize(T const)
{
    cout << "sizeof(data): " << sizeof(T) << endl;
}

template<typename T, typename std::enable_if_t<std::is_pointer<T>::value, int> = 0>
void CheckSize(T const)
{
    cout << "sizeof(data) (pointer): " << sizeof(std::remove_pointer<T>) << endl;
}

template<typename T, size_t N>
void CheckSize(T const (&)[N])
{
    cout << "sizeof(data) (array): " << sizeof(T) * N << endl;
}

int main()
{
    uint8_t bufferNumber{0};
    CheckSize(bufferNumber);
    uint8_t bufferArray[] = {1,2,3,4,5,6};
    CheckSize(bufferArray);
    uint8_t *bufferPointer{nullptr};
    CheckSize(bufferPointer);

    return 0;
}

我也不明白为什么编译器在编写时不能应用特化:

template<typename T>
void CheckSize(T const)
{
    cout << "sizeof(data): " << sizeof(T) << endl;
}

template<typename T>
void CheckSize(T const*)
{
    cout << "sizeof(data) (pointer): " << sizeof(T) << endl;
}

MSVC2015 将打印一条错误消息,指出函数调用对于 bufferArray 变量的重载函数不明确,MinGW 将使用 CheckSize(T const) 函数作为 bufferPointer 变量。

【问题讨论】:

  • Boost 提供了enable_if 和很多/所有可以在 C++98 中使用的特征。如果你必须使用 C++98 那么你应该考虑使用 boost 而不是自己尝试实现它。
  • 如果打印sizeof(T) * N,创建此模板有什么意义? sizeof(bufferArray) 提供相同的值。你想达到什么目标?
  • 这里只是示例代码。我需要数据的大小,因为我想在函数中使用底层数据(将其复制到缓冲区中)。

标签: c++ template-specialization c++98


【解决方案1】:

如 cmets 中所述,enable_if 和您使用的类型特征可以使用 C++98 实现。 Boost 提供了实现,如果您已经在使用 boost,我建议您使用它们,但如果您不使用 boost,它们的实现相当简单:

template <bool b, typename T>
struct enable_if;

template <typename T>
struct enable_if<true, T>
{
    typedef T type;
};

template <typename T>
struct is_pointer
{
    const static bool value = false;
};

template <typename T>
struct is_pointer<T*>
{
    const static bool value = true;
};

template <typename T>
struct remove_pointer
{
    typedef T type;
};

template <typename T>
struct remove_pointer<T*>
{
    typedef T type;
};

template<typename T>
typename enable_if<!is_pointer<T>::value, void>::type
CheckSize(T const)
{
    std::cout << "sizeof(data): " << sizeof(T) << std::endl;
}

template<typename T>
typename enable_if<is_pointer<T>::value, void>::type
CheckSize(T const)
{
    std::cout << "sizeof(data) (pointer): " << sizeof(typename remove_pointer<T>::type) << std::endl;
}

template<typename T, size_t N>
void CheckSize(T const (&)[N])
{
    std::cout << "sizeof(data) (array): " << sizeof(T) * N << std::endl;
}

Live Demo

或者,您可以使用部分专业化而不是 SFINAE 来选择您的重载。由于函数不能部分特化,您可以部分特化帮助器类:

template<typename T>
struct CheckSizeHelper
{
    static void size() {
        std::cout << "sizeof(data): " << sizeof(T) << std::endl;
    }
};

template<typename T>
struct CheckSizeHelper<T*>
{
    static void size() {
        std::cout << "sizeof(data) (pointer): " << sizeof(T) << std::endl;
    }
};

template<typename T, size_t N>
struct CheckSizeHelper<T[N]>
{
    static void size() {
        std::cout << "sizeof(data) (array): " << sizeof(T) * N << std::endl;
    }
};

template<typename T>
void CheckSize(T const&) {
    CheckSizeHelper<T>::size();
}

Live Demo

【讨论】:

    【解决方案2】:

    正如 cmets 中提到的,一种选择是使用 boost::enable_if

    另一种选择是对类使用部分模板特化而不是函数重载:

    #include <iostream>
    #include <type_traits>
    #include <cstdint>
    
    using namespace std;
    
    template<typename T>
    struct SizeChecker
    {
        static void CheckSize(T const)
        {
            cout << "sizeof(data): " << sizeof(T) << endl;
        }
    };
    
    template<typename T>
    struct SizeChecker<T*>
    {
        static void CheckSize(T* const)
        {
            cout << "sizeof(data) (pointer): " << sizeof(T*) << endl;
        }
    };
    
    template<typename T, size_t N>
    struct SizeChecker<T[N]>
    {
        static void CheckSize(const T(&)[N])
        {
            cout << "sizeof(data) (array): " << sizeof(T) * N << endl;
        }
    };
    
    template <typename T>
    void CheckSize(const T& val)
    {
        SizeChecker<T>::CheckSize(val);
    }
    
    int main()
    {
        char bufferNumber{0};
        CheckSize(bufferNumber);
        char bufferArray[] = {1,2,3,4,5,6};
        CheckSize(bufferArray);
        char *bufferPointer{NULL};
        CheckSize(bufferPointer);
    
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-10
      • 1970-01-01
      • 1970-01-01
      • 2011-02-07
      • 2014-12-15
      • 2019-07-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多