我想创建一个模板类,该模板类仅接受双向迭代器作为其构造函数中的参数(用于初始化其数据成员)。
我正在尝试为此使用 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被评估为false。
答案 0 :(得分:0)
首先,您正在反向使用特征。 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 */, "!");
};