7

我有一个问题,我需要检测给定类型是否是已知嵌套类型的实例,例如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;
}

但我收到编译器错误:

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

是否可以检查依赖类型,例如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())
}
4

3 回答 3

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

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

另一方面,您可能会以不同的方式解决此问题。例如,这是否是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;
}

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

希望能帮助到你。

于 2011-11-12T00:57:54.067 回答
1

AFAIK,您可以从中获取迭代器的值类型iterator_traits<Iter>::value_type。然后,您可以检查std::vector<that_value_type, Alloc>::iterator是否真的如此(例如 with boost::is_same

顺便说一句,从您的激励示例中,我可以看到您可能很难猜测Alloc-如果您不打算使用自定义分配器,则将其保留为默认值。没有适用于所有Allocs 的通用解决方案。

于 2011-11-12T00:49:30.050 回答
1

您应该从漂亮的打印机is_container_helper中查看typetrait 。在该库的更精致的公共版本中,我将 typetrait 称为(例如此处):has_const_iterator

template<typename T>
struct has_const_iterator
{
private:
    typedef char                      yes;
    typedef struct { char array[2]; } no;

    template<typename C> static yes test(typename C::const_iterator*);
    template<typename C> static no  test(...);
public:
    static const bool value = sizeof(test<T>(0)) == sizeof(yes);
    typedef T type;
};
于 2011-11-12T00:38:13.283 回答