模板函数使用for_each()和lambda函数打印C风格的数组

Kas*_*yap 3 c++ lambda stl-algorithm c++11

一件简单的事.但我花了一个小时才弄明白.

当我编译以下代码时:

#include <iostream>
#include <sort.h>
#define array_len(arr) ( sizeof(arr) / sizeof (*arr) )

using namespace std;

template<typename ITER>
void printIt_works(ITER b, ITER e) {
    for_each(b, e, [](int it) { cout << it; } ); // putting int explicitly would work
                                                 // but it's not generic
}

template<typename ITER>
void printIt_doesnt_work(ITER b, ITER e) {
    for_each(b, e, [](ITER it) { cout << *it; } );
}

int main() {
    int a[] = {5, 2, 4, 6, 1, 3};

    printIt_doesnt_work(a, a+array_len(a)); // how to make this work in a generic way.

    //merge_sort(a, a+array_len(a));
    selection_sort(a, 6);
    insertion_sort_decending(a, 6);
    insertion_sort(a, 6);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我得到的编译错误是:

In file included from d:\mingw\bin\../lib/gcc/mingw32/4.5.2/include/c++/algorithm:63:0,
                 from D:\Workspaces\CodeBlocks\Test\main.cpp:4:
d:\mingw\bin\../lib/gcc/mingw32/4.5.2/include/c++/bits/stl_algo.h: In function '_Funct std::for_each(_IIter, _IIter, _Funct) [with _IIter = int*, _Funct = printIt_doesnt_work(ITER, ITER) [with ITER = int*]::<lambda(int*)>]':
D:\Workspaces\CodeBlocks\Test\main.cpp:17:5:   instantiated from 'void printIt_doesnt_work(ITER, ITER) [with ITER = int*]'
D:\Workspaces\CodeBlocks\Test\main.cpp:23:42:   instantiated from here
d:\mingw\bin\../lib/gcc/mingw32/4.5.2/include/c++/bits/stl_algo.h:4185:2: error: invalid conversion from 'int' to 'int*'
d:\mingw\bin\../lib/gcc/mingw32/4.5.2/include/c++/bits/stl_algo.h:4185:2: error:   initializing argument 1 of 'printIt_doesnt_work(ITER, ITER) [with ITER = int*]::<lambda(int*)>'
Run Code Online (Sandbox Code Playgroud)

d:\ mingw\bin ../ lib/gcc/mingw32/4.5.2/include/c ++/bits/stl_algo.h:4185是for_each函数作为第3个参数传递给它的函数:__f(*__first);

我理解了这个问题,我的lambda函数被声明为期望int*但是for_each调用它的模板实例int.我只是不知道如何以某种generic方式解决它.

我当然可以通过使类型显式来解决,但这不是通用的:

for_each(b, e, [](int it) { cout << it; } );
Run Code Online (Sandbox Code Playgroud)

tem*_*def 6

一种选择是使用new decltype关键字来确定迭代内容的类型:

template<typename ITER>
void printIt_works(ITER b, ITER e) {
    for_each(b, e, [](decltype(*b) it) { cout << it; } );
}
Run Code Online (Sandbox Code Playgroud)

这使得一个lambda的参数类型是被迭代的类型,这正是你想要的.

如果decltype编译器上没有可用的,则可以使用bulkier iterator_traits类型执行此操作:

template<typename ITER>
void printIt_works(ITER b, ITER e) {
    for_each(b, e, [](typename std::iterator_traits<ITER>::reference it) { cout << it; } );
}
Run Code Online (Sandbox Code Playgroud)

但这真的很难看.

希望这可以帮助!

  • @thekashyap:请参阅[用于?的模板`typename`关键字是什么?](http://www.comeaucomputing.com/techtalk/templates/#typename) (2认同)

Phi*_*ipp 6

使用lambda函数的另一种方法是使用ostream_iterator:

#include <iterator>
#include <algorithm>

template<typename Iterator>
void printIt(const Iterator& begin, const Iterator& end) {
  typedef typename std::iterator_traits<Iterator>::value_type value_type;
  std::copy(begin, end, std::ostream_iterator<value_type>(cout));
}
Run Code Online (Sandbox Code Playgroud)