A simple thing. But I spent last one hour and couldn't figure out.
When I compile following code:
#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;
}
compilation error I get is:
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\bin../lib/gcc/mingw32/4.5.2/include/c++/bits/stl_algo.h:4185 is where for_each
calls the function passed to it as 3rd param: __f(*__first);
I understand the problem, my lambda function is declared to expect int*
but the template instance of for_each
calls it with int
. I just donno how to solve it in a generic
way.
I can of course work around by making type explicit, but that's not generic:
for_each(b, e, [](int it) { cout << it; } );
One option is to use the new decltype
keyword to determine the type of what's being iterated over:
template<typename ITER>
void printIt_works(ITER b, ITER e) {
for_each(b, e, [](decltype(*b) it) { cout << it; } );
}
This makes a lambda whose argument type is the type of what's being iterated over, which is precisely what you want.
If you don't have decltype
available on your compiler, you can use the bulkier iterator_traits
type to do this:
template<typename ITER>
void printIt_works(ITER b, ITER e) {
for_each(b, e, [](typename std::iterator_traits<ITER>::reference it) { cout << it; } );
}
But that's really ugly.
Hope this helps!