Исключение типа из шаблона класса

Вы можете использовать full_seq из tidyr - он был создан именно для таких задач ( Создать полную последовательность значений в векторе ):

library(tidyr)
library(dplyr)
df %>%
  group_by(id, group) %>%
  complete(year = full_seq(year, period = 1))

  id    group  year
  <fct> <fct> <dbl>
1 a     x      2000
2 a     x      2001
3 a     x      2002
4 a     x      2003
5 b     y      2003
6 b     z      2005
1
задан Comte_Zero 18 January 2019 в 23:28
поделиться

1 ответ

1126] Должен признать, что template все еще кажутся мне чёрной магией. Я успешно использовал специализации шаблона в различных ситуациях (если у меня не было лучшей идеи), но никогда не использовал аргументы шаблона. Итак, я попытался ...

Когда я попробовал coliru (компилятор g++ (GCC) 8.1.0), я начал с -std=c++11 и вскоре получил несколько ужасных ошибок. К счастью, был также совет перейти к -std=c++17. Я сделал, и вещи становятся намного лучше сразу. Я грубо вспомнил, что аргументы шаблона не очень хорошо поддерживаются в C ++ 11. Короткий взгляд на cppreference подтвердил мою правоту:

Параметр шаблона шаблона

template < список параметров> имя типа (C ++ 17) | имя класса (необязательно) (1)
шаблон < список параметров> имя типа (C ++ 17) | имя класса (необязательно) = default (2)
шаблон < список параметров> имя типа (C ++ 17) | class ... name (необязательно) (3) (начиная с C ++ 11)

1) Параметр шаблона шаблона с необязательным именем.
2) Параметр шаблона шаблона с необязательным именем и значением по умолчанию.
3) Пакет параметров шаблона шаблона с необязательным именем.

После разъяснения я взял часть кода кода OPs и добавил частичную специализацию для template, где я

  • оставил первый параметр
  • специализированный. второй параметр с std::stack.

На самом деле, это не сильно отличается от того, как специализируются шаблоны с аргументами типа или значения.

cppreference есть статья для этой частичной специализации шаблона , но при использовании этого термина в качестве ключевого слова для поиска должно быть много обращений к книгам и учебным пособиям. (Я помню книгу, в которой я когда-то учил шаблоны C ++, упомянул об этом также - конечно.)

Итак, вот мой небольшой пример, чтобы продемонстрировать это:

#include <iostream>
#include <stack>
#include <vector>

template<typename T, template <typename...> typename U>
class ContainerT {
  private:
    U<T> _container;
  public:
    ContainerT(): _container() { }
    ~ContainerT() = default;
    ContainerT(const ContainerT&) = default;
    ContainerT& operator=(const ContainerT&) = default;

    bool empty() const { return _container.empty(); }
    void push(const T &data) { _container.push_back(data); }
    T pop()
    {
      const T data = _container.back();
      _container.pop_back();
      return data;
    }
};

template<typename T>
class ContainerT<T, std::stack> {
  private:
    std::stack<T> _container;
  public:
    ContainerT(): _container() { }
    ~ContainerT() = default;
    ContainerT(const ContainerT&) = default;
    ContainerT& operator=(const ContainerT&) = default;

    bool empty() const { return _container.empty(); }
    void push(const T &data) { _container.push(data); }
    T pop()
    {
      const T data = _container.top();
      _container.pop();
      return data;
    }
};

#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__ 

int main()
{
  // for std::vector
  DEBUG(ContainerT<int, std::vector> vec);
  DEBUG(vec.push(1); vec.push(2); vec.push(3));
  DEBUG(while (!vec.empty()) std::cout << vec.pop() << '\n');
  // for std::stack
  DEBUG(ContainerT<int, std::stack> stk);
  DEBUG(stk.push(1); stk.push(2); stk.push(3));
  DEBUG(while (!stk.empty()) std::cout << stk.pop() << '\n');
  // done
  return 0;
}

Очевидно, что [1110 ] создан для ContainerT<int, std::vector>. В противном случае метод push() не может быть скомпилирован.

Для ContainerT<int, std::stack> вместо этого используется специализация. (Опять же, в противном случае метод push() не может быть скомпилирован.)

Вывод:

ContainerT<int, std::vector> vec;
vec.push(1); vec.push(2); vec.push(3);
while (!vec.empty()) std::cout << vec.pop() << '\n';
3
2
1
ContainerT<int, std::stack> stk;
stk.push(1); stk.push(2); stk.push(3);
while (!stk.empty()) std::cout << stk.pop() << '\n';
3
2
1

Live Demo на колиру

0
ответ дан Scheff 18 January 2019 в 23:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: