【问题标题】:C++ template specialization for iterators迭代器的 C++ 模板特化
【发布时间】:2014-11-30 22:59:11
【问题描述】:

我想交换由迭代器指向的 2 个值。所以我想专门化模板函数来获取迭代器。请告诉我,我该怎么做?

非迭代器的功能:

template <typename T>
void exch(T &a, T &b)
{
    T c( std::move(a) );
    a = std::move(b);
    b = std::move(c);   
}

迭代器的功能:

template <typename It>
void exch(It &a, It &b)
{
    auto c( std::move(*a) );
    *a = std::move(*b);
    *b = std::move(c);   
}

当然,有 2 个函数我得到一个错误:

/projects/DFSTL/main.cpp:17:6: 错误:'template void exch(It&, It&)'的重新定义

【问题讨论】:

  • SFINAE 或 is_iterator 特征上的标签调度,其实现可以很容易地在 SO 上找到。但是你确定你真的想这样做吗?如果有人真的想交换迭代器怎么办?
  • 你可以使用std::iter_swap()

标签: c++ templates c++11 swap


【解决方案1】:

我建议不要这样做——交换ab,并交换ab 间接引用的东西,这是一件很容易超载的事情。但如果你这样做,你最终会得到非常奇怪的行为。

如果必须,第一步将涉及编写自己的 is_iterator 特征类。这可以通过各种方法来完成。一种适用于某些编译器的方法是使用 std::iterator_traits&lt;It&gt;::iterator_category 的 SFINAE 分辨率,并检查 input_iterator_tagoutput_iterator_tag 是否是该类型的基础。

您通常需要检测 void* 和 cv 变体。这仍然是实现定义的行为,因为非迭代器上的std::iterator_traits 会生成实现定义的结果。

更复杂的方法是检查迭代器的每个类型公理并测试它们,如果都通过就说它是一个迭代器。

一旦你有了is_iterator&lt;T&gt;,你就可以使用SFINAE了:

template <class T, class=std::enable_if_t< !is_iterator<std::decay_t<T>>{} >>
void exch(T &a, T &b) {
  using std::swap;
  swap(a,b);
}

迭代器的功能:

template <class It, class=std::enable_if_t< is_iterator<std::decay_t<It>>{} >>
void exch(It a, It b) {
  using std::iter_swap;
  iter_swap(a,b);
}

请注意,我在启用 ADL 的上下文中调用了 swapiter_swap,并使用 std:: 查找而不是手动实现它。这允许在其封闭命名空间中专门化自己的 swap 的类型自动获得更优化的解决方案。

【讨论】:

    【解决方案2】:

    这两个模板函数看起来与编译器相同。这就是你得到编译器错误的原因。

    您是否尝试过使用此功能:std::swap()

    它看起来像你想要的那样 - 并且已经专门针对所有 STL 容器类型进行交换有意义。

    【讨论】:

    • 是的,我知道=) 但是我正在尝试编写自己的并行 STL 实现 ^__^,以便学习它们并成为模板中的专家=)
    猜你喜欢
    • 2014-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-27
    • 2014-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多