2012-03-14 8 views
3

簡単なことです。しかし、私は最後の1時間を費やし、把握できませんでした。for_each()とlambda関数を使用してCスタイルの配列を出力するテンプレート関数

私は次のコードをコンパイルするとき:

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

を私が手にコンパイルエラーがある:

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*)>' 

D:\ mingwのの\ビン../ libに/ gccを/ MINGW32/4.5.2 /含めます/c++/bits/stl_algo.h:4185はfor_eachが3番目のパラメータとして渡された関数を呼び出す場合です:__f(*__first);

私のラムダ関数は期待通りに宣言されていますint*ですが、for_eachのテンプレートインスタンスはintで呼び出します。私はちょうどgenericの方法でそれを解決する方法をdonno。

タイプ明示的にすることによって、周りの私はコースワークのできる

が、それは一般的なではありません。

for_each(b, e, [](int it) { cout << it; }); 
+0

:http://www.cplusplus.com/reference/std/iterator/iterator_traits/ – Anycorn

+2

そのマクロを使用して配列の長さを取得しないでください。テンプレート size_t al(T(&)[N]){return N; }、あなたのマクロは、ポインタに適用されてコンパイルされますが、意図したように動作しないため。 – PlasmaHH

+0

@PlasmaHHありがとうございました。私は実際にそのようなものを探していました。:) – Kashyap

答えて

6

1つのオプションは、繰り返し処理されているものの種類を決定するために、新しいdecltypeキーワードを使用することです:

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

これは、引数の型が繰り返し処理されるものの型であるラムダを作成します。これは正確に必要なものです。

あなたのコンパイラでdecltypeが使用できない場合、あなたはこれを行うにはかさばる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; }); 
} 

をしかし、それは本当に醜いです。

希望すると便利です。

+0

そして、それらが多形ラムダを実際に行うなら、それは次のようになります: 'for_each(b、e、[](auto i){cout << i;});' – bames53

+0

ありがとう、私はASAを受け入れるので、私に許可します。 :)... 2番目のオプションでは、なぜ 'typename'が必要ですか? 'iterator_traits'は' typedef T&reference; 'を定義しているのですが、なぜ' [](std :: iterator_traits :: reference it) 'というエラーが出ます:エラー: 'std :: iterator_traits <_Iter> :: reference'は型ではありません – Kashyap

+0

@ありがとう。その( 'auto')有効な構文か、stdが望むものが許されますか? "エラー:パラメータが 'auto'と宣言されています。 – Kashyap

5

ラムダ関数を使用する代わりに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)); 
} 
+0

私の目的は、配列、STL algos、イテレータの使い方を学ぶことでした。しかし、ありがとう。 :) – Kashyap