c++ - 当模板参数是双向迭代器时,如何启用模板类专业化?
问题描述
我想创建一个模板类,它只接受双向迭代器作为其构造函数中的参数(用于初始化其数据成员)。
我正在尝试为此使用enable_if和iterator_category,但我不明白出了什么问题。我在带有-std=c++17的 Linux 上同时使用 gcc 8.3.1 和 clang 7 。我还在Compiler Explorer上尝试过其他编译器。
(注意:我也尝试过使用is_same_v而不是is_base_of_v,但结果相同,或者缺少...)
#include <iterator>
#include <type_traits>
#include <vector>
template<typename It>
using it_cat = typename std::iterator_traits<It>::iterator_category;
template<typename BidIt,
typename std::enable_if_t<std::is_base_of_v<it_cat<BidIt>, std::bidirectional_iterator_tag>> = 0
>
class A {
BidIt start;
public:
// A() : start {} {}
A(BidIt s_) : start {s_} {}
};
// A<std::vector<int>::iterator> a1;
int main()
{
std::vector<int> v {0, 1, 2, 3};
A a2 {v.begin()};
}
注释的两行试图通过显式传递参数(没有成功)手动实例化 A 类型的空对象。编译器输出清楚地表明类型推导失败:
error: no type named 'type' in 'struct std::enable_if<false, void>'
typename std::enable_if_t<std::is_base_of_v<it_cat<BidIt>, std::bidirectional_iterator_tag>> = 0
据我了解, enable_if 被评估为假。
解决方案
首先,您正在向后使用该特征。std::is_base_of<Base, Derived>
检查第一个是否是第二个的基础。所以你的支票应该是is_base_of_v<bidirectional_iterator_tag, it_cat<BidIt>>
.
其次,执行这种条件启用的 C++17 习语(假设您想要其他专业化)是有一个默认的第二个模板参数:
template <typename T, typename Enable = void>
struct X; // the primary
template <typename T>
struct X<T, std::enable_if_t</* condition */>> // the conditional specialization
{ ... };
如果您不需要其他专业,我们可以通过更简单的方式来做到这一点:
template <typename T>
struct X {
static_assert(/* the condition */, "!");
};
推荐阅读
- javascript - Java Script 按值过滤嵌套对象属性
- c# - NullableAttribute 在另一个模块中声明,需要导入 - ILRepack
- c# - Razor-pages 通过 HttpClient 使用凭据上传文件
- python - 在多索引熊猫数据框中添加每个级别 2 索引的总数
- php - Laravel 安装程序在创建新项目时抛出错误
- android - android:nextFocusDown 在 viewpager 中不起作用
- php - 在heroku中播种数据透视表导致错误
- javascript - Javascript 错误地解码 unicode
- jquery - jQuery - 使用子 div 值对父 div 进行排序不起作用
- html - 如何创建带有外部圆形 div 的配置文件下拉菜单?