Специализированные шаблоны для указателей и переменных массива в стиле c - PullRequest
2 голосов
/ 11 апреля 2019

У меня есть следующий код, который работает, когда я компилирую код с включенным 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.

Ответы [ 2 ]

2 голосов
/ 11 апреля 2019

Как уже упоминалось в комментариях, 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

1 голос
/ 11 апреля 2019

Как уже упоминалось в комментариях, одним из вариантов является использование 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;
}
...