Quiero pasar una función sobrecargada al std::for_each()
algoritmo. Por ejemplo,
class A {
void f(char c);
void f(int i);
void scan(const std::string& s) {
std::for_each(s.begin(), s.end(), f);
}
};
Esperaría que el compilador se resuelva f()
por el tipo de iterador. Aparentemente, (GCC 4.1.2) no lo hace. Entonces, ¿cómo puedo especificar cuál f()
quiero?
Respuestas:
Puede usar
static_cast<>()
para especificar cuálf
usar de acuerdo con la firma de función implícita en el tipo de puntero de función:O también puedes hacer esto:
Si
f
es una función miembro, entonces debe usarmem_fun
, o para su caso, usar la solución presentada en este artículo del Dr. Dobb .fuente
f()
es miembro de una clase (vea el ejemplo editado arriba)reinterpret_cast
. Muy a menudo veo moldes de estilo C utilizados para esto. Mi regla es que los lanzamientos en punteros de función son peligrosos e innecesarios (como muestra el segundo fragmento de código, existe una conversión implícita).std::for_each(s.begin(), s.end(), static_cast<void (A::*)(char)>(&A::f));
Lambdas al rescate! (nota: se requiere C ++ 11)
O usando decltype para el parámetro lambda:
Con lambdas polimórficas (C ++ 14):
O desambiguate eliminando la sobrecarga (solo funciona para funciones gratuitas):
fuente
mem_fn
ybind
, por cierto, también C ++ 11). Además, si queremos ser realmente pedantes, tenemos[&](char a){ return f(a); }
28 caracteres ystatic_cast<void (A::*)(char)>(&f)
35 caracteres.¿Por qué no funciona?
¡Sería genial si ese fuera el caso! Sin embargo,
for_each
es una plantilla de función, declarada como:La deducción de plantilla debe seleccionar un tipo
UnaryFunction
en el punto de la llamada. Perof
no tiene un tipo específico: es una función sobrecargada, hay muchosf
s cada uno con diferentes tipos. No hay una forma actual defor_each
ayudar al proceso de deducción de plantillas al indicar cuálf
quiere, por lo que la deducción de plantillas simplemente falla. Para que la deducción de la plantilla sea exitosa, debe trabajar más en el sitio de la llamada.Solución genérica para arreglarlo
Saltando aquí unos años y C ++ 14 más tarde. En lugar de usar un
static_cast
(que permitiría que la deducción de plantillas tenga éxito al "arreglar" lof
que queremos usar, pero requiere que usted haga manualmente la resolución de sobrecarga para "arreglar" la correcta), queremos que el compilador funcione para nosotros. Queremos recurrirf
a algunos argumentos. De la manera más genérica posible, eso es:Eso es mucho para escribir, pero este tipo de problema surge de manera molesta con frecuencia, por lo que podemos envolverlo en una macro (suspiro):
y luego solo utilízalo:
Esto hará exactamente lo que desearía que hiciera el compilador: realizar una resolución de sobrecarga en el nombre
f
mismo y simplemente hacer lo correcto. Esto funcionará independientemente de sif
es una función libre o una función miembro.fuente
No para responder a tu pregunta, pero ¿soy el único que encuentra
tanto más simple como más corto que la
for_each
alternativa sugerida por in silico en este caso?fuente
El problema aquí parece no ser la resolución de sobrecarga sino la deducción de parámetros de plantilla . Si bien la excelente respuesta de @In silico resolverá un problema de sobrecarga ambiguo en general, parece que la mejor solución cuando se trata
std::for_each
(o similar) es especificar explícitamente sus parámetros de plantilla :fuente
Si no te importa usar C ++ 11, aquí hay un ayudante inteligente que es similar (pero menos feo que) al reparto estático:
(Funciona para funciones miembro; debe ser obvio cómo modificarlo para que funcione para funciones independientes, y debe poder proporcionar ambas versiones y el compilador seleccionará la correcta para usted).
Gracias a Miro Knejp por sugerir: ver también https://groups.google.com/a/isocpp.org/d/msg/std-discussion/rLVGeGUXsK0/IGj9dKmSyx4J .
fuente
R
, no se deduce. Tampoco hay mención de eso en esta respuesta.R
, estoy proporcionandoArgs
.R
yT
se deducen Es cierto que la respuesta podría mejorarse. (No hay ningunoT
en mi ejemplo, porque no es un puntero a miembro, porque eso no funcionaríastd::for_each
).