【问题标题】:How to enable a template class specialization when the template parameter is a bidirectional_iterator?当模板参数是双向迭代器时,如何启用模板类特化?
【发布时间】:2019-04-09 14:06:07
【问题描述】:

我想创建一个模板类,它只接受双向迭代器作为其构造函数中的参数(用于初始化其数据成员)。

我正在尝试为此使用 enable_ifiterator_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。

【问题讨论】:

  • 投票结束是一个错字。 std::is_base_of_v 的参数是向后的,&gt; = 0 应该是 &gt;* = nullptr

标签: c++ c++17 sfinae


【解决方案1】:

首先,您正在反向使用 trait。 std::is_base_of&lt;Base, Derived&gt; 检查第一个是否是第二个的基础。所以你的支票应该是is_base_of_v&lt;bidirectional_iterator_tag, it_cat&lt;BidIt&gt;&gt;

其次,执行这种条件启用的 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 */, "!");
};

【讨论】:

  • 对 is_base_of 上的错字/干扰表示歉意。但是,这个解决方案仍然对我不起作用。我应该在条件特化中使用什么样的条件?现在它失败了``` :11:7: note: template argument deduction/substitution failed: :29:20: note: '__gnu_cxx::__normal_iterator >' 不是派生自 'A' A a2 {v.begin()}; ```
  • @JoeSilver 您之前打算使用的相同条件:is_base_of_v&lt;bidirectional_iterator_tag, it_cat&lt;Iter&gt;&gt;
  • 是的,谢谢,它可以工作,但前提是我创建了一个 A 类型的对象并传递了一个显式的模板参数:A&lt;vector&lt;int&gt;::iterator&gt; a1 {v.begin()}。我试图使用类型推导,但在我的尝试中仍然不起作用。
  • @JoeSilver 您真的需要有条件启用的专业化吗?如果您只使用static_assert,事情会简单得多。否则,你需要一个扣除指南。
  • 好吧,我真的需要它,事实上它毕竟是一个静态检查。我试图在没有概念的情况下模拟类似概念的条件
猜你喜欢
  • 2011-05-10
  • 1970-01-01
  • 1970-01-01
  • 2021-12-26
  • 2018-11-26
  • 1970-01-01
  • 2018-06-25
  • 1970-01-01
  • 2015-02-19
相关资源
最近更新 更多