从类模板中排除类型

时间:2019-01-18 22:20:31

标签: c++ templates

我目前无法stack弄乱我的一个模板化类。
问题是pusk_backbeginend之类的方法不适用于该类型。
因此,我的目标是防止用stack<T>实例化包含或添加防止stack实例到达代码的那些部分的条件。
class如下所示:

template<typename T, template <typename...> typename U>
class contain {
    public:
        contain() : _container()
        {
        }
        ~contain()
        {
        }
        void push(T const&data)
        {
            this->_container.push_back(data);
        }
        void aff()
        {
            std::for_each(_container.begin(), _container.end(),
            [](T &var) {::aff(var);});
        }
        void add()
        {
            std::for_each(_container.begin(), _container.end(),
            [](T &var) {::add(var);});
        }
    private:
        U<T> _container;
};

我试图专门化模板,但是找不到语法,也无法在运行时检查变量的类型。

1 个答案:

答案 0 :(得分:1)

我必须承认template仍然对我来说有点像黑魔法。我已经成功地在各种情况下使用了模板专业化(如果我没有更好的主意),但是从来没有使用模板参数。所以,我尝试了...

当我尝试使用coliru(编译器g++ (GCC) 8.1.0)时,我从-std=c++11开始,很快遇到了一些可怕的错误。幸运的是,也有切换到-std=c++17的提示。我做到了,情况马上好起来了。我大概记得在C ++ 11中不完全支持模板模板参数。简短浏览cppreference,就证明我是对的:

  

Template template parameter

     

模板<参数列表>类型名(C ++ 17)|类名(可选)(1)
  模板<参数列表>类型名(C ++ 17)|类名称(可选)=默认(2)
  模板<参数列表>类型名(C ++ 17)| class ... name(可选)(3)(自C ++ 11起)

     

1)具有可选名称的模板模板参数。
  2)具有可选名称和默认名称的模板template参数。
  3)带有可选名称的模板模板参数包。

在澄清了这一点之后,我参加了OP的示例代码,并为template添加了部分专业化知识,其中我

  • 离开第一个参数
  • 使用std::stack专业化第二个参数。

实际上,这与带有类型或值参数的模板的专业化没有什么不同。

cppreference对此 partial template specialization 发表了一篇文章,但使用该词作为搜索关键字,应该会引起很多书籍和教程的点击。 (我记得我曾经从中学习过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;
}

很明显ContainerTContainerT<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 on coliru