C ++模板+迭代器(noob问题)

时间:2009-10-20 18:48:00

标签: c++ templates iterator

我的免责声明是我在一周前开始自学C ++课程,而我以前的编程经验是使用动态语言(Python,javascript)。

我正在尝试使用通用函数迭代矢量内容以打印出项目:

#include <iostream>
#include <algorithm>
#include <vector>

using std::vector;
using std::cout;

template <class T>
void p(T x){
    cout << x;
}

int main () {

    vector<int> myV;

    for(int i = 0; i < 10; i++){
        myV.push_back(i);
    }

    vector<int>::const_iterator iter = myV.begin();

    for_each(iter, myV.end(), p);

    return 0;
}

代码无法编译。有人解释原因吗?

编辑:编译器错误:

  

error: no matching function for call to 'for_each(_gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<const int, _gnu_norm::vector<int, std::allocator<int> > >, __gnu_debug_def::vector<int, std::allocator<int> > >&, __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<int, __gnu_norm::vector<int, std::allocator<int> > >, __gnu_debug_def::vector<int, std::allocator<int> > >, <unknown type>)'

谢谢!

4 个答案:

答案 0 :(得分:13)

尝试:

for_each(myV.begin(), myV.end(), p<int>);

您的代码中有两个错误:

  • 迭代器的类型不同
  • 函数指针实际上不是指针。
    • 通常模板化的函数可以从那里参数推导出来。但在这种情况下,您实际上并没有使用它,而是将它(或其地址)传递给函数(因此模板函数推导的常规规则不起作用)。由于编译器无法推断出您需要使用哪个版本的函数'p',因此必须明确。

还有一个很好的输出迭代器可以做到这一点:

std::copy(myV.begin(),myV.end(), std::ostream_iterator<int>(std::cout));

另请注意,很少有编译器可以在函数指针调用中优化代码 虽然如果它是一个仿函数对象,大多数都能够优化调用。因此,以下可能是函数指针的可行替代方法:

template<typename T>
struct P
{
    void operator()(T const& value) const
    {
        std::cout << value;
    }
};

....

for_each(myV.begin(), myV.end(), P<int>());

另一个注意事项:
使用模板化方法/函数时,通常使用const引用而不是值。如果要复制的类型很昂贵,那么按值传递将生成一个可能不符合预期的复制结构。

答案 1 :(得分:3)

Martin的解决方案起作用而你的解决方案不起作用的原因是p是一个功能模板,而不是一个实际的功能。模板函数没有可以采用的地址,也没有传递给函数。您必须实例化模板函数,以创建可以使用的实际函数。

答案 2 :(得分:1)

您的问题是您必须将一些“可调用实体”传递给std::for_each。这可能是一个函数对象(这是一个重载函数调用操作符的类)或一个函数指针。 (无论何处需要函数指针,您都可以使用匹配的原型传递函数的名称 - 函数名称会隐式转换为函数地址。)

但是,您的p不是函数,而是函数模板。功能模板就是:用于创建函数的模板。您需要传递这样一个创建的函数而不是模板的名称。让编译器从函数模板创建函数的机制通常称为模板实例化。所以你需要一个模板实例。无论何时使用这样的实例,都会由编译器隐式创建。

因此,正如其他人已经说过的那样,您需要明确地将p<int>传递给std::foreach

std::for_each(myV.begin(), myV.end(), p<int>);

答案 3 :(得分:0)

我没有在C ++中使用过for_each,但我会编写相同的循环:

vector<int>::iterator iter;

for(iter = myV.begin(); iter != myV.end(); iter++) {
    p(iter);
}