c++ - 从类模板中排除类型
问题描述
我目前在stack
弄乱我的一个模板类时遇到了麻烦。
问题是pusk_back
,begin
或end
不适用于该类型的方法。
所以我的目标是防止包含被实例化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;
};
我试图专门化模板,但找不到语法,也无法在运行时检查变量的类型。
解决方案
我必须承认,template
对我来说,s 仍然有点像黑魔法。我已经在各种情况下成功地使用了模板特化(如果我没有更好的主意的话),但从来没有使用模板参数。所以,我试了...
当我尝试使用 coliru(编译器g++ (GCC) 8.1.0
)时,我开始使用-std=c++11
并很快遇到了一些可怕的错误。幸运的是,还有一个提示可以切换到-std=c++17
. 我做到了,事情立刻变得好多了。我大致记得模板模板参数在 C++11 中没有得到很好的支持。一眼就cppreference
证明了我是对的:
模板 <参数列表> 类型名 (C++17) | 类名(可选)(1)
模板<参数列表>类型名(C++17)| 类名(可选) = 默认 (2)
模板 < 参数列表 > 类型名 (C++17) | 类 ... 名称(可选) (3) (C++11 起)1) 具有可选名称的模板模板参数。
2) 具有可选名称和默认值的模板模板参数。
3) 具有可选名称的模板模板参数包。
澄清这一点后,我编写了部分 OP 示例代码,并为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;
}
很明显,这ContainerT
是为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
推荐阅读
- ruby-on-rails - 是否应该在关联请求外键值后自动更新输入表单?
- c++ - 链接器错误 - 不确定它没有链接什么
- python - 如何通过python在excel中按字母顺序对列进行排序?
- typescript - 在打字稿中返回两种类型的函数
- java - 如何调试 java.lang.StringIndexOutOfBoundsException:字符串索引超出范围错误?
- android - 如何在android中设置大于100的进度条的最大值
- elasticsearch - 是否可以在 ElasticSearch 的聚合脚本中访问日期范围值?
- amazon-web-services - 在 S3 上列出文件夹
- c# - 无法解析表达式'...:给定的参数与预期的参数不匹配”
- python-3.x - 如何在pytorch的Unet中使用PNASNet5作为编码器