如何在编译时检查类型是否为std :: vector :: iterator?

Jar*_*ock 7 c++ template-meta-programming

我有一个问题,我需要检测给定类型是否是已知嵌套类型的实例,如std::vector::iterator在编译时.我想创建类型特征is_std_vector_iterator:

#include <type_traits>
#include <vector>

template<typename T> struct is_std_vector_iterator : std::false_type {};

template<typename T, typename Allocator>
  struct is_std_vector_iterator<typename std::vector<T,Allocator>::iterator>
    : std::true_type
{};

int main()
{
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

但我收到编译器错误:

$ g++ -std=c++0x test.cpp 
test.cpp:7: error: template parameters not used in partial specialization:
test.cpp:7: error:         ‘T’
test.cpp:7: error:         ‘Allocator’
Run Code Online (Sandbox Code Playgroud)

是否可以检查依赖类型std::vector<T,Allocator>::iterator


这是一个激发这种特质的用例:

template<typename Iterator>
Iterator my_copy(Iterator first, Iterator last, Iterator result, std::true_type)
{
  // iterators are just pointer wrappers; call memcpy
  memcpy(&*result, &*first, sizeof(typename Iterator::value_type) * last - first);
  return result + last - first;
}

template<typename Iterator>
Iterator my_copy(Iterator first, Iterator last, Iterator result, std::false_type)
{
  // use a general copy
  return std::copy(first, last, result);
}

template<typename Iterator>
Iterator my_copy(Iterator first, Iterator last, Iterator result)
{
  // dispatch based on the type of Iterator
  return my_copy(first, last, result, typename is_std_vector_iterator<Iterator1>::type())
}
Run Code Online (Sandbox Code Playgroud)

小智 3

好吧,在最简单的情况下,它可能看起来像这样:

#include <type_traits>
#include <vector>
#include <list>
#include <cstdio>

template <typename T>
typename std::enable_if<
    std::is_same<typename std::vector<typename T::value_type>::iterator, T>::value
    , void>::type
do_something (T begin, T end)
{
    std::printf ("Got vector iterators!\n");
}

template <typename T>
typename std::enable_if<
    !std::is_same<typename std::vector<typename T::value_type>::iterator, T>::value
    , void>::type
do_something (T begin, T end)
{
    std::printf ("Got something other than vector iterators!\n");
}

template <typename T>
typename std::enable_if<std::is_pod<T>::value, void>::type
do_something (T begin, T end)
{
    std::printf ("Got some POD iterators!\n");
}

int main()
{
    std::vector<int> ivec;
    std::list<int> ilist;
    char cdata[64];

    do_something (ivec.begin (), ivec.end ());
    do_something (ilist.begin (), ilist.end ());
    do_something (&cdata[0], cdata + 32);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但当有人决定使用与默认分配器不同的分配器时,真正的问题就出现了。由于您想要针对某些众所周知的类型(而不是众所周知的模板)检查迭代器,那么您基本上可以使用它,并可能使用您知道的一些分配器来扩展它。否则,用不同类型实例化的模板是不同的类型,我不确定是否有方法来测试类型是否是专门使用某些任意参数的模板的实例,可能没有这样的方法。

另一方面,您可以用不同的方式解决这个问题。例如,这是否是std::vector<...>迭代器有什么区别?检查它是否是随机访问等可能是有意义的。

更新:

对于连续布局的内存,我认为最好的选择是使用迭代器特征并检查随机访问标记。例如:

#include <type_traits>
#include <functional>
#include <vector>
#include <list>
#include <cstdio>

template <typename T>
struct is_random_access_iterator : std::is_same<
    typename std::iterator_traits<T>::iterator_category
    , std::random_access_iterator_tag>
{};

template <typename T>
typename std::enable_if<is_random_access_iterator<T>::value>::type
do_something (T begin, T end)
{
    std::printf ("Random access granted!\n");
}

template <typename T>
typename std::enable_if<!is_random_access_iterator<T>::value>::type
do_something (T begin, T end)
{
    std::printf ("No random access for us today!\n");
}

int main()
{
    std::vector<int> ivec;
    std::list<int> ilist;
    char cdata[32];

    do_something (ivec.begin (), ivec.end ());
    do_something (ilist.begin (), ilist.end ());
    do_something (&cdata[0], cdata + sizeof (cdata) / sizeof (cdata[0]));

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这肯定比使用std::vector分配器进行检查更简单,甚至更可靠。然而,即使在这种情况下,如果有人真的愿意,也可以欺骗你,购买为你提供随机访问迭代器,它提供对不同内存块的无缝访问,一旦你将其转换为指针,使用指针算术而不是迭代器,你就会遇到大问题重载的运算符。您只能通过在更改原始指针和迭代器时比较内存地址来保护自己免受这种情况的影响,但没有任何效果。

希望能帮助到你。