Как иметь шаблоны с типом и размером? - PullRequest
2 голосов
/ 29 марта 2019

Просто ради удовольствия я пытаюсь перегрузить struct, один для std::array<T,SIZE>, один для std::vector<T> и std::unordered_map<T,U>. Поэтому я сделал следующее:

  template<typename... T>
  struct Cont; 

  template<typename T, std::size_t SIZE>
  struct Cont<T,SIZE>
  {
    Cont(std::string n) : name(n){}

    std::string name;
    std::array<T,SIZE> array;
  };

  template<typename T>
  struct Cont<T>
  {
    Cont(std::string n) : name(n){}

    std::string name;
    std::vector<T> vector;
  };

  template<typename T, typename U>
  struct Cont<T,U>
  {
    Cont(std::string n) : name(n){}

    std::string name;
    std::unordered_map<T,U> unordered_map;
  };

Однако, когда я пытаюсь его скомпилировать, я получаю ошибку expected a type, got SIZE. Что я полностью понимаю, так это то, что typename... T ожидает тип, а не std::size_t. Итак, я попробовал:

template<std::size_t SIZE, typename... T>
struct Cont;

template<typename... T>
struct Cont;

Что также не работает, так как я переопределяю и не перегружаю, как я изначально думал, что делал. Я также понимаю, что я могу сделать:

template<std::size_t SIZE, typename... T>
struct Cont;

Однако я стараюсь сохранить это как можно более чистым в том смысле, когда я объявляю их, я хочу быть в состоянии сделать:

int main()
{
  Cont<int,5> myArray("myArray");
  myArray.array = {1,2,3,4,5};

  Cont<int> myVector("myVector");
  myVector.vector = {1,2,3,4};

  Cont<int,int> myMap("myMap");
  myMap.unordered_map[0] = 2;
}

Есть ли способ перегрузить шаблон? (Я предполагаю, что это не так) или создать шаблон таким образом, что я либо typename... T или typename T, std::size_t SIZE?

Ответы [ 3 ]

2 голосов
/ 29 марта 2019

Я не уверен, как получить именно то, что вы хотите. Возможно, у более умного пользователя есть точное решение. Но одна альтернатива может состоять в том, чтобы просто иметь пакет параметров типа для вашего шаблона и использовать std::integral_constant s для ваших числовых аргументов шаблона. Тогда вы могли бы специализироваться для каждого случая. Например:

#include <array>
#include <type_traits>
#include <unordered_map>
#include <vector>

template<class...>
struct Cont;

template<class T, class U, U S>
struct Cont<T, std::integral_constant<U, S>>
{
    Cont(const char *) {};
    std::array<T, S> array;
};

template<class T>
struct Cont<T>
{
    Cont(const char *) {};
    std::vector<T> vector;
};

template<class T>
struct Cont<T, T>
{
    Cont(const char *) {};
    std::unordered_map<T, T> unordered_map;
};

int main()
{
  Cont<int,std::integral_constant<int, 5>> myArray("myArray");
  myArray.array = {1,2,3,4,5};

  Cont<int> myVector("myVector");
  myVector.vector = {1,2,3,4};

  Cont<int,int> myMap("myMap");
  myMap.unordered_map[0] = 2;
}
1 голос
/ 30 марта 2019

Если вы объявите версию массива следующим образом

template <typename T, std::size_t SIZE>
struct Cont<std::array<T, SIZE>>
{
  Cont(std::string n) : name(n) {}

  std::string name;
  std::array<T, SIZE> array;
};

Тогда в основном вы можете использовать его следующим образом:

int main() {
  Cont<std::array<int, 5>> myArray("myArray");
  myArray.array = {1, 2, 3, 4, 5};

  Cont<int> myVector("myVector");
  myVector.vector = {1, 2, 3, 4};

  Cont<int, int> myMap("myMap");
  myMap.unordered_map[0] = 2;

  std::cout << "myArray " << myArray.array[0] << std::endl;
  // myArray 1

  std::cout << "myVector " << myVector.vector[0] << std::endl;
  // myVector 1

  std::cout << "myMap " << myMap.unordered_map[0] << std::endl;
  // myMap 2
}

Я думаю, что это та функция, которую вы ищете, ион чистый и читаемый.

Это работает, потому что std::array<int, 5> называет тип, которого ожидает template <typename... T>, и содержит информацию std::SIZE_T, необходимую для определения std::array.

1 голос
/ 29 марта 2019

Вы могли бы сделать это Cont<std::array<int, 5>>, а затем иметь специализацию template<typename T, std::size_t SIZE> struct Cont<std::array<T, SIZE>>;, но это нарушает структуру других типов.

Еще одна вещь, которую вы можете иметь, - помимо преобразования 5 в тип путем обертывания его в std::integral_constant, создать пару перегруженных вспомогательных функций, которые автоматически сделают это за вас:

template<typename... T>
Cont<T...> make_cont(std::string name) {
    return { std::move(name) };
}

template<typename T, std::size_t SIZE>
Cont<T, std::integral_constant<std::size_t, SIZE>> make_cont(std::string name) {
    return { std::move(name) };
}

int main() {
    auto myArray = make_cont<int, 5>("myArray");
    myArray.array = {1,2,3,4,5};

    auto myVector = make_cont<int>("myVector");
    myVector.vector = {1,2,3,4};

    auto myMap = make_cont<int, int>("myMap");
    myMap.unordered_map[0] = 2;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...