簡體   English   中英

如何在編譯時檢查類型是否為std :: vector :: iterator?

[英]How to check whether a type is std::vector::iterator at compile time?

我有一個問題,我需要在編譯時檢測給定類型是否是已知嵌套類型的實例,如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())
}

那么,在最簡單的情況下,它可能看起來像這樣:

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

這個將比使用allocator檢查std::vector更簡單,更加可靠。 然而,即使在這種情況下,有人可以欺騙你,如果他們真的想要,購買提供隨機訪問迭代器,提供無縫訪問不同的內存塊,一旦你將其轉換為指針使用指針算術而不是迭代器,你將遇到大問題重載運營商。 只有在更改原始指針和迭代器時比較內存地址,才能保護自己免受攻擊,但是沒有果汁。

希望能幫助到你。

您應該從漂亮的打印機查看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;
};

AFAIK,您可以從iterator_traits<Iter>::value_type獲取iterator_traits<Iter>::value_type的值類型。 然后,您可以檢查std::vector<that_value_type, Alloc>::iterator是否真的如此(例如,使用boost::is_same

從您的激勵示例來看,我可以看到您可能會有猜測Alloc麻煩 - 如果您不打算使用自定義分配器,您只需將其保留為默認值。 沒有適用於所有Alloc的通用解決方案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM