2013-05-08 2 views
2

Я хочу объявить алгоритм, который принимает пару итераторов и критерий. Затем он возвращает вектор элементов из диапазона итераторов, которые соответствуют критерию.Как объявить этот алгоритм?

template <typename TIterator, typename TCriterium> 
std::vector< Type that I will get after dereferencing TIterator > 
filter (TIterator begin, TIterator end, TCriterium passes); 

Я могу использовать возможности C++ 11, такие как decltype или auto. Я пробовал:

#include <vector> 

template <typename TIterator, typename TCriterium> 
auto filter (TIterator begin, TIterator end, TCriterium passes) 
         -> std::vector< decltype(*begin) > 
{ 
} 

int main() 
{ 
    std::vector<int*> vector; 
    filter(vector.begin(), vector.end(), 0); 
    return 0; 
} 

Но это не работает. Я получаю:

/usr/include/c++/4.7/ext/new_allocator.h:59: 
error: forming pointer to reference type 'int*&' 
+1

Заметим, что [˙copy_if'] (http://en.cppreference.com/w/cpp/algorithm/copy) ведет себя почти то же самое, только то, что вам нужно передать выходной итератор. – jrok

ответ

6

Вы могли бы использовать:

std::vector<typename std::iterator_traits<TIterator>::value_type> 

В качестве типа возвращаемого вашей функции, которые затем стали:

#include <vector> 
#include <iterator> 

// ... 

template <typename TIterator, typename TCriterium> 
std::vector<typename std::iterator_traits<TIterator>::value_type> filter(
    TIterator begin, TIterator end, TCriterium passes) 
{ 
    // Body... 
} 

Если вы хотите пойти decltype путь, то вы можете сделать:

#include <vector> 
#include <type_traits> 

// ... 

template <typename TIterator, typename TCriterium> 
auto filter (TIterator begin, TIterator end, TCriterium passes) 
    -> std::vector< typename std::decay<decltype(*begin)>::type > 
{ 
} 
+0

Спасибо! Это действительно компилируется и работает так, как я хочу, чтобы он работал. –

+0

@MartinDrozdik: Рад, что это помогло :) –

+2

Но это не удастся, если 'TIterator' является реальным указателем (' int * '). Как насчет использования 'std :: iterator_traits :: value_type'? – rodrigo

1

Возможно, вы посмотрите на std::remove_reference и заголовок type_traits для управления типами

+0

О, так вот почему мой код не компилируется? –

1

Используйте std::vector<typename std::iterator_traits<TIterator>::value_type> или, возможно, std::vector<typename std::decay<decltype(*begin)>::type>. Я бы предпочел первый.

+0

Зачем вам совет 'std :: decay', а не' std :: remove_reference'? Кажется слегка «подавленным». –

+2

Если переданный итератор является const_iterator, оператор * возвращает const T &, а remove_reference превратит это в const T. Вы не хотите вектор . Подумайте об этом, iterator_traits :: value_type может быть const для const_iterators. –

+0

Ах! Я не думал о проблемах 'const'. Я не думаю, что 'value_type' будет' const'. Они, как правило, «голые», вероятно, именно по этой причине. –

2

*begin является ссылкой, так что вам нужно удалить, что:

-> std::vector< std::remove_reference<decltype(*vector)>::type > 

хотя, прочитав другие ответы, я бы, вероятно, предпочитают использовать iterator_traits здесь.

1

Вы можете использовать std::iterator_traits получить тип используемого итератора:

template <typename TIterator, typename TCriterium> 
auto filter (TIterator begin, TIterator end, TCriterium passes) 
        -> std::vector<std::iterator_traits<TIterator>::value_type> 
Смежные вопросы