Cuando defino esta función,C++ 11 no deduce tipo cuando las funciones std :: función o lambda están involucrados
template<class A>
set<A> test(const set<A>& input) {
return input;
}
I puede llamar usando test(mySet)
en otra parte en el código sin tener que definir explícitamente la tipo de plantilla Sin embargo, cuando se utiliza la siguiente función:
template<class A>
set<A> filter(const set<A>& input,function<bool(A)> compare) {
set<A> ret;
for(auto it = input.begin(); it != input.end(); it++) {
if(compare(*it)) {
ret.insert(*it);
}
}
return ret;
}
Cuando llamo a esta función utilizando filter(mySet,[](int i) { return i%2==0; });
me sale el siguiente error:
error: no matching function for call to ‘filter(std::set&, main()::)’
Sin embargo, todas estas versiones hacer trabajo:
std::function<bool(int)> func = [](int i) { return i%2 ==0; };
set<int> myNewSet = filter(mySet,func);
set<int> myNewSet = filter<int>(mySet,[](int i) { return i%2==0; });
set<int> myNewSet = filter(mySet,function<bool(int)>([](int i){return i%2==0;}));
¿Por qué C++ 11 no puede adivinar el tipo de plantilla cuando puse la función lambda directl y dentro de la expresión sin crear directamente un std::function
?
EDIT:
por consejo de Luc Danton en los comentarios, aquí es una alternativa a la función que tenía anteriormente que no necesita las plantillas para pasar de forma explícita.
template<class A,class CompareFunction>
set<A> filter(const set<A>& input,CompareFunction compare) {
set<A> ret;
for(auto it = input.begin(); it != input.end(); it++) {
if(compare(*it)) {
ret.insert(*it);
}
}
return ret;
}
Esto se puede llamar set<int> result = filter(myIntSet,[](int i) { i % 2 == 0; });
sin necesidad de la plantilla.
El compilador puede incluso adivinar los tipos de devolución hasta cierto punto, utilizando la nueva palabra clave decltype y utilizando la nueva función tipografía de devolución de tipo. Este es un ejemplo que convierte un conjunto de un mapa, utilizando una función de filtrado y una función que genera las claves en base a los valores:
template<class Value,class CompareType,class IndexType>
auto filter(const set<Value>& input,CompareType compare,IndexType index) -> map<decltype(index(*(input.begin()))),Value> {
map<decltype(index(*(input.begin()))),Value> ret;
for(auto it = input.begin(); it != input.end(); it++) {
if(compare(*it)) {
ret[index(*it)] = *it;
}
}
return ret;
}
También puede ser llamado sin usar directamente la plantilla, como
map<string,int> s = filter(myIntSet,[](int i) { return i%2==0; },[](int i) { return toString(i); });
No relacionado con su pregunta, pero se da cuenta de que su 'filtro' es esencialmente equivalente a una versión no genérica de' std :: copy_if', ¿no? –
Ah, no estaba al tanto de std :: copy_if, gracias por señalarlo. Sin embargo, esto es parte de un grupo más grande de 4 funciones, una que convierte set => map durante el filtrado y no veo una forma de implementar eso con copy_if y permitir que el usuario produzca claves usando los valores en el conjunto. Por consistencia en el uso, estoy optando por hacerlo de esta manera. – Datalore
Para el registro, si desea aceptar un funtor, generalmente es idiomático hacerlo un parámetro de plantilla general, es decir 'plantilla establecer filtro (establecer const & input, comparar predicado);'. Como acaba de ver, 'std :: function' no funciona para documentar que el predicado pasado debe tener una firma que coincida con' bool (A) '; hay otras formas de hacerlo. Además, hay * otras * desventajas en el uso de 'std :: function' como argumento de función. –