简体   繁体   English

函数模板接受的不是双向迭代器或指针

[英]Function template accepting nothing less than a bidirectional iterator or a pointer

I need a function template that accepts two iterators that could be pointers. 我需要一个函数模板,它接受两个可能是指针的迭代器。 If the two arguments are random_access iterators I want the return type to be an object of 如果两个参数是random_access迭代器,我希望返回类型是一个对象

std::iterator<random_access_iterator_tag, ...> type std::iterator<random_access_iterator_tag, ...>类型

else a 否则一个

std::iterator<bidirectional_iterator_tag, ...> type. std::iterator<bidirectional_iterator_tag, ...>类型。

I also want the code to refuse compilation if the arguments are neither a bidirectional iterator, nor a pointer. 如果参数既不是双向迭代器也不是指针,我也希望代码拒绝编译。 I cannot have dependency on third party libraries eg Boost 我不能依赖第三方库,例如Boost

Could you help me with the signature of this function so that it accepts bidirectional iterators as well as pointers, but not say input_iterator, output_iterator, forward_iterators. 你能帮助我使用这个函数的签名,以便它接受双向迭代器和指针,但不是说input_iterator,output_iterator,forward_iterators。

One partial solution I can think of is the following 我能想到的一个部分解决方案如下

template<class T>
T foo( T iter1, T iter2) {
  const T tmp1 = reverse_iterator<T>(iter1);
  const T tmp2 = reverse_iterator<T>(iter2);
  // do something
}

The idea is that if it is not bidirectional the compiler will not let me construct a reverse_iterator from it. 我的想法是,如果它不是双向的,编译器就不会让我从中构造一个reverse_iterator。

Here's an example with enable_if based on iterator tags. 这是一个基于迭代器标记的enable_if示例。 The substitution fails if the given T doesn't have a iterator_category typedef and so that overload isn't considered during overload resolution. 如果给定的T没有iterator_category typedef,则替换失败,因此在重载解析期间不考虑重载。

Since you can't use C++11, see the reference pages for enable_if and is_same to see how you can implement it by yourself. 由于您无法使用C ++ 11,请参阅enable_ifis_same的参考页面,了解如何is_same实现它。

#include <iterator>
#include <type_traits>
#include <iostream>
#include <vector>
#include <list>

template<typename T>
typename
std::enable_if<
    std::is_same<
        typename T::iterator_category,
        std::bidirectional_iterator_tag
    >::value,
    T
>::type
foo(T it)
{
    std::cout << "bidirectional\n";
    return it;
}

template<typename T>
typename
std::enable_if<
    std::is_same<
        typename T::iterator_category,
        std::random_access_iterator_tag
    >::value,
    T
>::type
foo(T it)
{
    std::cout << "random access\n";
    return it;
}

// specialization for pointers

template<typename T>
T* foo(T* it)
{
    std::cout << "pointer\n";
    return it;
}

int main()
{
    std::list<int>::iterator it1;
    std::vector<int>::iterator it2;
    int* it3;
    std::istream_iterator<int> it4;
    foo(it1);
    foo(it2);
    foo(it3);
    //foo(it4); // this one doesn't compile, it4 is an input iterator
}

Live example . 实例

As per @JonathanWakely's comment, we can get rid of specialization for pointers if we use std::iterator_traits . 根据@ JonathanWakely的评论,如果我们使用std :: iterator_traits ,我们可以摆脱指针的特化。 The typename T::iterator_category part then becomes 然后, typename T::iterator_category部分成为

typename std::iterator_traits<T>::iterator_category

a bit simpler than previous answer, no dependency on std::enable_if: 比以前的答案简单一点,不依赖于std :: enable_if:

namespace detail
{
    template<class T>
    T do_foo(T iter1, T iter2, std::random_access_iterator_tag t)
    {
        cout << "do_foo random_access" << endl;
        return iter1;
    }
    template<class T>
    T do_foo(T iter1, T iter2, std::bidirectional_iterator_tag t)
    {
        cout << "do_foo bidirectional" << endl;
        return iter1;
    }

}
template<class T>
void foo(T iter1, T iter2)
{
    typename std::iterator_traits<T>::iterator_category t;
    detail::do_foo(iter1, iter2, t);
}

int main (int argc, const char * argv[])
{
    std::vector<int> v;
    foo(v.begin(), v.end());
    std::list<int> l;
    foo(l.begin(), l.end());
    return 0;
}

The solution also supports other iterator_categories derived from std::random_access_iterator_tag or std::bidirectional_iterator_tag (should there be any), while std::same<> checks for strict category equality. 该解决方案还支持从std :: random_access_iterator_tag或std :: bidirectional_iterator_tag派生的其他iterator_categories(如果有的话),而std :: same <>检查严格类别相等。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 仅接受非整数类型的函数模板(特别是双向迭代器) - Function template accepting only non integral types (specifially bidirectional iterators) 成员函数接受模板函数指针时出现问题 - Trouble with member function accepting template function pointer 模板参数接受指向类成员函数的指针 - Template parameter accepting pointer to class member function 在模板函数中自动将指针/迭代器转换为const - Automatically convert pointer/iterator to const in template function 与将条件作为模板参数传递给sort()的比较导致比将条件函数指针传递给qsort()更少的开销? - Comparison with passing criteria as template parameter to sort() results in less overhead than passing criteria function pointer to qsort()? 为什么C ++模板接受数组不比一个接受指针(bis)更专业? - Why C++ template accepting array is not more specialized than one accepting pointer (bis)? 声明一个接受泛型迭代器的函数 - Declare a function accepting generic iterator 函数指针接受参数 - Function pointer accepting argument 可以将原始指针传递给期望迭代器的模板函数吗? - Can a raw pointer be passed to a template function expecting an iterator? 为什么接受数组的C ++模板不比根据GCC 5.3和Clang 4.0接受指针的数组更专业? - Why is a C++ template accepting an array not more specialized than one accepting a pointer according to GCC 5.3 and Clang 4.0?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM