2015-02-05 2 views
2

Я новичок в функции шаблона и не могу понять эту ошибку. Надеюсь, ты поможешь.Как правильно вызвать функцию шаблона?

#include <iostream> 
#include <vector> 

/* 
* Print to the screen the content of a vector 
* Define function template in the header 
*/ 
template <typename T> void print_vector(T& v) { 
    for(typename std::vector<T>::const_iterator i = v.begin(); i != v.end(); ++i) 
     std::cout << *i << ' '; 
} 

int main() { 
    std::vector<int> field; 
    field.resize(12, 1); 

    /* 
    for(std::vector<int>::const_iterator i = field.begin(); i != field.end(); ++i) 
     std::cout << *i << ' '; 
    */ 

    print_vector(field); 
} 

Мой код не удалось скомпилировать с очень длинным сообщением об ошибке, которое я даже не могу вставить здесь.

error: conversion from ‘std::vector<int>::iterator {aka __gnu_cxx::__normal_iterator<int*, std::vector<int> >}’ to non-scalar type ‘std::vector<std::vector<int>, std::allocator<std::vector<int> > >::const_iterator {aka __gnu_cxx::__normal_iterator<const std::vector<int>*, std::vector<std::vector<int>, std::allocator<std::vector<int> > > >}’ requested 
utility.h:21:59: error: no match for ‘operator!=’ in ‘i != (& v)->std::vector<_Tp, _Alloc>::end<int, std::allocator<int> >()’ 
utility.h:21:59: note: candidates are: 
In file included from /usr/include/x86_64-linux-gnu/c++/4.7/./bits/c++allocator.h:34:0, 
       from /usr/include/c++/4.7/bits/allocator.h:48, 
       from /usr/include/c++/4.7/string:43, 
       from /usr/include/c++/4.7/bits/locale_classes.h:42, 
       from /usr/include/c++/4.7/bits/ios_base.h:43, 
       from /usr/include/c++/4.7/ios:43, 
       from /usr/include/c++/4.7/istream:40, 
       from /usr/include/c++/4.7/fstream:40, 
       from utility.h:4: 
/usr/include/c++/4.7/ext/new_allocator.h:134:5: note: template<class _Tp> bool __gnu_cxx::operator!=(const __gnu_cxx::new_allocator<_Tp>&, const __gnu_cxx::new_allocator<_Tp>&) 
/usr/include/c++/4.7/ext/new_allocator.h:134:5: note: template argument deduction/substitution failed: 
utility.h:21:59: note: ‘std::vector<std::vector<int>, std::allocator<std::vector<int> > >::const_iterator {aka __gnu_cxx::__normal_iterator<const std::vector<int>*, std::vector<std::vector<int>, std::allocator<std::vector<int> > > >}’ is not derived from ‘const __gnu_cxx::new_allocator<_Tp>’ 
+0

В сигнатуре функции вы должны иметь 'std :: vector &' как тип параметра, а не 'T &'. – leemes

+1

Для чего он стоит, у C++ нет функций шаблона, у него есть «шаблоны функций». Это действительно очень важная разница. В C++ у вас есть шаблоны * для * функций, т. Е. Шаблон, из которого компилятор создает функции, а не функции, которые являются шаблонами. –

ответ

4

Когда вы звоните

std::vector<int> field; 
... 
print_vector(field); 

T в print_vector является тип field, т.е. std::vector<int>. Таким образом, в typename std::vector<T>::const_iterator

for(typename std::vector<T>::const_iterator i = v.begin(); 

std::vector<std::vector<int> >::const_iterator является, к которому v.begin() (само является std::vector<int>::iterator) не является конвертируемым. Использовать

for(typename T::const_iterator i = v.begin(); 

вместо этого.

То есть: в функции, которая создана из шаблона функции print_vector для этого случая.

1

В функции:

template <typename T> 
void print_vector(T& v) { 
    for(typename std::vector<T>::const_iterator i = v.begin(); i != v.end(); ++i) 
     std::cout << *i << ' '; 
} 

T выводится в std::vector<int>, так что вы пытаетесь преобразовать std::vector<int>::iterator (результат v.begin()) в std::vector<std::vector<int>>::const_iterator (типа i), которая не является действительное преобразование.

Вместо этого, просто сделать более специализированную функцию шаблона:

template <typename T> 
void print_vector(std::vector<T>& v) { 
    // as before 
} 
0

Вы назвали функцию должным образом. Но тогда вы путаете шаблон-аргумент (тип контейнера) с типом-контейнером.

В любом случае, нет причин для этого не быть const.

Таким образом, он должен выглядеть следующим образом, вместо:

template <typename T> void print_vector(const T& v) { 
    for(typename T::const_iterator i = v.begin(); i != v.end(); ++i) 
     std::cout << *i << ' '; 
} 

Или используя стандартную библиотеку и лямбды:

template <typename T> void print_vector(const T& v) { 
    using std::begin; // Using ADL for begin and end to support raw arrays 
    using std::end; 
    std::for_each(begin(v), end(v), [](auto&& x){std::cout<<*i<<' ';}); 
} 

Или с помощью auto и диапазона для петель (мой любимый):

template <typename T> void print_vector(const T& v) { 
    for(auto&& i : v) 
     std::cout << *i << ' '; 
} 

Или с помощью C++ 1Z (прогнозируемое на 2017 год):

void print_vector(const auto& v) { 
    for(auto&& i : v) 
     std::cout << *i << ' '; 
} 
+0

Последний ('for (i: v)') был отклонен на последнем заседании комитета. –

+0

@ T.C .: Почему они отвергли это? Вы знаете? – Deduplicator

+1

Я думаю, что из-за опасений, что он объявит (и потенциально тень) что-то, не выглядя как декларация. После 'int i = 0; вектор v {1}; для (i: v); ',' i' по-прежнему 0. –

0

Либо заменить std::vector<T>::const_iterator i с просто T::const_iterator i, если вы хотите, чтобы передать его любой итерацию, или специализироваться его соответствующим образом с void print_vector(std::vector<T>& v), если вы хотите для него, чтобы работать только с векторами любых типов.

Если вы запустите подстановку, как сейчас, вы увидите, что вы даете вектор чему-то, создающему вектор из этого типа, следовательно, получив вектор вектора.

Также GCC 4.8 и 4.9 имеют улучшенные сообщения и добавляют более точную ошибку. Если вы не можете переместить компилятор, что понятно, тогда вы всегда можете подавать такие небольшие фрагменты в онлайн-формате, как ideone.com. Ошибка, скорее всего, была намного более сжатой и читаемой в 4.8.

О, и если у вас есть доступ к функциям C++ 11 (я не помню, что сделало это в 4.7), вы можете автоматизировать объявления типов и использовать что-то вроде cbegin() вместо того, чтобы начать получать разрешение типа выбрать const_iterator вместо обычного. Если вы изучаете шаблоны и не имеете ограничений рабочей среды, я настоятельно рекомендую перейти на C++ 11 и более новый GCC, это облегчит процесс упрощения.

Смежные вопросы