Проверьте, является ли тип экземпляром шаблона

Я хочу проверить, является ли тип экземпляром конкретного шаблона во время компиляции.

Например:

  1. std::vector<int> - это экземпляр std::vector
  2. std::array<int, 5> является экземпляром std::array

Я могу сделать тест, который работает для случая 1, но не работает для случая 2.

#include <iostream>
#include <type_traits>
#include <string>
#include <vector>
#include <array>
#include <queue>
template<template<typename...> class, typename...>
struct is_instantiation : public std::false_type {};

template<template<typename...> class U, typename... T>
struct is_instantiation<U, U<T...>> : public std::true_type {};

int main() {
    using A = std::vector<int>;
    std::cout << is_instantiation<std::vector, A>::value << "\n";
    std::cout << is_instantiation<std::queue, A>::value << "\n";
    // std::cout << is_instantiation<std::array, A>::value << "\n";
}

Как заставить его работать в обоих случаях?

Я пробовал авто, но не могу заставить его работать.

Преимущества авто в параметрах шаблона в С++ 17

Ответы

Ответ 1

Spezialized std :: размер массива

Единственный способ, который я вижу, - создать специализированные классы Array с заранее заданными размерами массива. Что-то вроде этого:

#include <iostream>
#include <type_traits>
#include <string>
#include <vector>
#include <array>
#include <queue>
template<template<typename...> class, typename...>
struct is_instantiation : public std::false_type {};

template<template<typename...> class U, typename... T>
struct is_instantiation<U, U<T...>> : public std::true_type {};

template <class T> class My5Array {
    public:
    My5Array() { }
    private:
    std::array<T, 5> arr;
};

template <class T> class My10Array {
    public:
    My10Array() { }
    private:
    std::array<T, 10> arr;
};

int main() {
    using A = std::vector<int>;
    using B = My5Array<int>;
    std::cout << is_instantiation<std::vector, A>::value << "\n";
    std::cout << is_instantiation<std::queue, A>::value << "\n";
    std::cout << is_instantiation<My5Array, A>::value << "\n";
    std::cout << is_instantiation<My5Array, B>::value << "\n";
    std::cout << is_instantiation<My10Array, B>::value << "\n";
}

печать

1
0
0
1
0

Конечно, есть недостатки:

  • возможно, потеря памяти из-за размера фиксированной матрицы
  • для требуемых размеров массива требуются несколько классов
  • использование нестандартного типа MyXArray
  • очевидно, что экземпляр My5Array не может быть экземпляром My10Array в одно и то же время (см. var B в коде выше)

1-я возможная альтернатива: std :: dynarray

Я также нашел std :: dynarray, который мог бы работать вместо std :: array, но я думаю, что он еще не включен в последние C++ стандарты. Возможно, стоит обратить на это внимание.

Вторая возможная альтернатива: просто отпустите ее

Стандартный доступный контейнер, возможно, достаточен для большинства приложений.