如何正确调用模板函数?

时间:2015-02-05 16:55:18

标签: c++ templates c++11 stl

我是模板功能的新手,无法解决此错误。希望你能帮忙。

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

4 个答案:

答案 0 :(得分:4)

致电时

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

T 1 中的print_vectorfield的类型,即std::vector<int>。因此,{/ 1}}

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

代替。

1 也就是说:在本案例的函数模板for(typename T::const_iterator i = v.begin(); 中创建的函数中。

答案 1 :(得分: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>::iteratorv.begin()的结果)转换为std::vector<std::vector<int>>::const_iterator(类型) i),这不是有效的转换。

相反,只需创建一个更专业的模板函数:

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

答案 2 :(得分:0)

您正确调用了该功能。但是后来你把template-argument(容器的类型)和容器元素类型混淆了。

无论如何,它没有理由不是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 << ' ';
}

或者使用标准库和lambdas:

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和range-for-loops(我最喜欢的):

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

答案 3 :(得分:0)

如果您希望将std::vector<T>::const_iterator i传递给任何可迭代的,请将T::const_iterator i替换为void print_vector(std::vector<T>& v),或者如果您希望它仅适用于任何类型的矢量,请使用{{1}}进行适当的专门化。

如果您现在运行替换,您将看到您正在为该类型创建向量的内容提供向量,从而获得向量的向量。

GCC 4.8和4.9也改进了消息并添加了更精确的错误插入符号。 如果你不能移动编译器,这是可以理解的,那么你总是可以将像这样的小片段提供给像ideone.com这样的在线片段。在4.8中,错误很可能更简洁,更易读。

哦,如果您可以访问C ++ 11的功能(我不记得4.7中的内容),您可以自动执行这些类型声明并使用类似cbegin()的内容而不是开始获取类型决定选择const_iterator而不是正常的const_iterator。如果您正在学习模板,并且没有工作环境限制,我强烈建议您转移到C ++ 11和更新的GCC,它将使缓存变得更加容易。