如何在编译时检查类型是否为std :: vector :: iterator? [英] How to check whether a type is std::vector::iterator at compile time?

查看:152
本文介绍了如何在编译时检查类型是否为std :: vector :: iterator?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a problem where I need to detect whether a given type is an instance of a known nested type such as std::vector::iterator at compile time. I'd like to create the type trait 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;
}

但我收到编译器错误:

$ 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’


b $ b

有可能检查一个依赖类型,如 std :: vector< T,Allocator> :: iterator

这是一个这样的特质的激励用例:

Here's a motivating use case of such a trait:

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())
}


推荐答案

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

Well, in the simplest case scenario it could look something like this:

#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;
}

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

But the real problem comes when someone decides to use allocator different from default one. Since you want to check iterator against some well known type, not a well known template, then you can basically use this and possibly extend it with some allocators that you are aware of. Otherwise, a template instantiated with different types is a different type, and I am not sure if there is a way to test if a type is an instance of template specialized with some arbitrary parameter, there is probably no such way.

另一方面,你可能会不同地解决这个问题。例如,它是不是它是否是 std :: vector< ...> 迭代器的不同?

On the other hand, you may solve this problem differently. For example, what difference it makes whether this is std::vector<...> iterator or not? It might make sense to check whether it is random access or not, etc.

UPDATE:

对于连续布局的内存,我想说最好的办法是使用迭代器traits并检查随机访问标记。例如:

For continuously laid out memory, I'd say the best bet is to use iterator traits and check for random access tag. For example:

#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;
}

这样会比检查<$ c更简单, $ c> std :: vector 和分配器。然而,即使在这种情况下,有人可以欺骗你,如果他们真的想要,提供你随机访问迭代器,提供无缝访问不同的内存块,你会有很大的问题,一旦你转换为指针使用指针算术而不是迭代器重载运算符。你可以通过比较内存地址,同时更改原始指针和迭代器,保护自己,但没有果汁。

This one will be definitely simpler and even more solid than checking against std::vector with allocators. However, even in this case someone can fool you if they really want, buy providing you random access iterator that provides seamless access to different chunks of memory, and you will have big problems once you convert that into a pointer use pointer arithmetics rather than iterator's overloaded operators. You can protect yourself against that only by comparing memory addresses while changing both raw pointer and iterator, but there is no juice.

希望它有帮助。

这篇关于如何在编译时检查类型是否为std :: vector :: iterator?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆