【问题标题】:How to restrict template parameter to pointer or random access iterator only?如何仅将模板参数限制为指针或随机访问迭代器?
【发布时间】:2014-05-14 21:01:53
【问题描述】:

有没有办法将模板函数的参数类型限制为仅指针或随机访问迭代器?

假设我正在开发一个仅适用于随机可访问容器的排序功能。如果用户通过非随机访问迭代器,我正在寻找一种引发编译时错误的方法。

#include <type_traits>
#include <iterator>

template <class Iterator> void mySort(Iterator begin, Iterator end){

    /*The below condition must be true if the 'Iterator' type is a pointer 
    or if it is of Category random_access_iterator_tag. How to make such check?*/
    static_assert(some condition, "The mySort() function only accepts random access iterators or raw pointers to an array.\n");

    for (Iterator it = begin; it != end; ++it){
        /*Some kind of sorting is performed here, which 
        uses arithmetic operators + and - in the iterator type. */
    }
}

我知道要检查一个类型是否是指针,我可以使用std::is_pointer&lt;Iterator&gt;::value 并检查迭代器是否是随机访问,我可以使用std::is_same&lt;std::random_access_iterator_tag, Iterator::iterator_category&gt;::value

第一个问题是两个检查都应该在同一个static_assert() 内进行或运算,否则如果其中一个匹配,另一个不匹配。

第二个问题是,如果要以这种方式调用函数,随机访问检查将失败:mySort&lt;int*&gt;(...)。这显然是因为int* 没有::iterator_category 定义。

有人知道如何解决这个问题吗? 我也知道编译器会在尝试将算术运算符与非随机访问迭代器一起使用时自动抛出错误,但我想通过static_assert() 显示更全面的错误消息。

作为后续问题。如果'Iterator'是指针类型,有没有办法断言它是原始类型(非struct/class)?

提前谢谢你。

【问题讨论】:

  • 我看不出第一个“问题”是个问题。你能解释一下吗?
  • 我指的是如果我要使用两个 static_asserts(这是我的第一个想法),每个检查一个,一个会失败。更准确地说,以以下方式断言:static_assert(std::is_same&lt;std::random_access_iterator_tag, Iterator::iterator_category&gt;::value, "") and static_assert(std::is_pointer&lt;Iterator&gt;::value, "") 将导致以下调用失败(我不希望他们这样做):mySort&lt;int*&gt;(...) mySort&lt;std::vector&lt;int&gt;::iterator&gt;(...) 不过,使用 Dieter 的解决方案这显然不再是问题! std::iterator_traits 完成了这项工作!

标签: c++ c++11 static-assert


【解决方案1】:

使用迭代器特征:

static_assert(
    std::is_same<std::random_access_iterator_tag,
                 typename std::iterator_traits<Iterator>::iterator_category>::value,
    "The mySort() function only accepts random access iterators or raw pointers to an array.\n");

【讨论】:

  • 你最好使用 is_convertible 而不是 is_same,因为open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3884.pdf 会发生什么仍然未知。
  • +1 我已经使用 SFINAE 和部分专业化编写了一个答案,但这显然是要走的路:标准库为此目的提供了 std::iterator_traits。不要重新发明轮子
  • @Nevin 'is_convertible' 可能是一个选项,但这里的连续内存没有问题。
  • 是的,但是对于指针、向量/字符串迭代器等,random_access_iterator 标签可能会更改为 contiguous_iterator_tag。
  • @DieterLücking:由于我是那篇论文的作者,您的反馈已被记录并认真考虑。 (不破坏向后兼容性的唯一方法是引入一个包含标签的单独特征,但该讨论超出了 OP 在此处提出的问题。)
猜你喜欢
  • 1970-01-01
  • 2021-03-02
  • 1970-01-01
  • 2014-07-13
  • 2012-08-19
  • 2020-04-23
  • 1970-01-01
  • 2015-10-18
相关资源
最近更新 更多