sirven que punteros para matrices los lenguaje funciones declaracion con aritmetica c++ stl

c++ - que - punteros void lenguaje c



¿Cómo especifico un puntero a una función sobrecargada? (6)

Por qué no funciona

Esperaría que el compilador resolviera f() por el tipo de iterador. Aparentemente, (gcc 4.1.2) no lo hace.

Sería genial si ese fuera el caso! Sin embargo, for_each es una plantilla de función, declarada como:

template <class InputIterator, class UnaryFunction> UnaryFunction for_each(InputIterator, InputIterator, UnaryFunction );

La deducción de la plantilla debe seleccionar un tipo para la función UnaryFunction en el momento de la llamada. Pero f no tiene un tipo específico, es una función sobrecargada, hay muchas f s cada una con diferentes tipos. No existe una forma actual para que cada for_each ayude al proceso de deducción de la plantilla indicando qué f quiere, por lo que la deducción de la plantilla simplemente falla. Para que la deducción de la plantilla tenga éxito, debe hacer más trabajo en el sitio de llamadas.

Solución genérica para arreglarlo

Salto aquí unos años y C ++ 14 más tarde. En lugar de usar static_cast (lo que permitiría que la deducción de la plantilla static_cast éxito al "arreglar" lo que queremos usar, pero requiere una resolución de sobrecarga manual para "corregir" la correcta), queremos que el compilador funcione para nosotros . Queremos llamar f a algunos argumentos. De la manera más genérica posible, eso es:

[&](auto&&... args) -> decltype(auto) { return f(std::forward<decltype(args)>(args)...); }

Eso es mucho para tipear, pero este tipo de problema aparece con frecuencia molesto, así que podemos envolverlo en una macro (suspiro):

#define AS_LAMBDA(func) [&](auto&&... args) -> decltype(func(std::forward<decltype(args)>(args)...)) { return func(std::forward<decltype(args)>(args)...); }

y luego solo úsalo:

void scan(const std::string& s) { std::for_each(s.begin(), s.end(), AS_LAMBDA(f)); }

Esto hará exactamente lo que usted desea que haga el compilador: realice la resolución de sobrecarga en el nombre f mismo y simplemente haga lo correcto. Esto funcionará independientemente de si f es una función libre o una función miembro.

Quiero pasar una función sobrecargada al algoritmo std::for_each() . 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 resolviera f() por el tipo de iterador. Aparentemente, (GCC 4.1.2) no lo hace. Entonces, ¿cómo puedo especificar qué f() quiero?


El problema aquí parece no ser la resolución de sobrecarga, sino la deducción del parámetro de la plantilla . Si bien la respuesta excelente de @In silico resolverá un problema de sobrecarga ambigua en general, parece que la mejor solución cuando se trata con std::for_each (o similar) es especificar explícitamente sus parámetros de plantilla :

// Simplified to use free functions instead of class members. #include <algorithm> #include <iostream> #include <string> void f( char c ) { std::cout << c << std::endl; } void f( int i ) { std::cout << i << std::endl; } void scan( std::string const& s ) { // The problem: // error C2914: ''std::for_each'' : cannot deduce template argument as function argument is ambiguous // std::for_each( s.begin(), s.end(), f ); // Excellent solution from @In silico (see other answer): // Declare a pointer of the desired type; overload resolution occurs at time of assignment void (*fpc)(char) = f; std::for_each( s.begin(), s.end(), fpc ); void (*fpi)(int) = f; std::for_each( s.begin(), s.end(), fpi ); // Explicit specification (first attempt): // Specify template parameters to std::for_each std::for_each< std::string::const_iterator, void(*)(char) >( s.begin(), s.end(), f ); std::for_each< std::string::const_iterator, void(*)(int) >( s.begin(), s.end(), f ); // Explicit specification (improved): // Let the first template parameter be derived; specify only the function type std::for_each< decltype( s.begin() ), void(*)(char) >( s.begin(), s.end(), f ); std::for_each< decltype( s.begin() ), void(*)(int) >( s.begin(), s.end(), f ); } void main() { scan( "Test" ); }


Lambdas al rescate! (nota: se requiere C ++ 11)

std::for_each(s.begin(), s.end(), [&](char a){ return f(a); });

O usando decltype para el parámetro lambda:

std::for_each(s.begin(), s.end(), [&](decltype(*s.begin()) a){ return f(a); });

Con lambdas polimórficas (C ++ 14):

std::for_each(s.begin(), s.end(), [&](auto a){ return f(a); });

O desambiguación eliminando la sobrecarga (solo funciona para funciones gratuitas):

void f_c(char i) { return f(i); } void scan(const std::string& s) { std::for_each(s.begin(), s.end(), f_c); }


No responder su pregunta, pero ¿soy el único que encuentra

for ( int i = 0; i < s.size(); i++ ) { f( s[i] ); }

¿Tanto más simple como más corta que la alternativa para for_each alternativa sugerida por in silico en este caso?


Puede usar static_cast<>() para especificar qué f usar de acuerdo con la firma de la función implicada por el tipo de puntero a función:

// Uses the void f(char c); overload std::for_each(s.begin(), s.end(), static_cast<void (*)(char)>(&f)); // Uses the void f(int i); overload std::for_each(s.begin(), s.end(), static_cast<void (*)(int)>(&f));

O bien, también puedes hacer esto:

// The compiler will figure out which f to use according to // the function pointer declaration. void (*fpc)(char) = &f; std::for_each(s.begin(), s.end(), fpc); // Uses the void f(char c); overload void (*fpi)(int) = &f; std::for_each(s.begin(), s.end(), fpi); // Uses the void f(int i); overload

Si f es una función miembro, entonces necesita usar mem_fun , o para su caso, use la solución presentada en este artículo del Dr. Dobb .


Si no te importa usar C ++ 11, aquí hay un ayudante inteligente que es similar (pero menos feo que) al elenco estático:

template<class... Args, class T, class R> auto resolve(R (T::*m)(Args...)) -> decltype(m) { return m; } template<class T, class R> auto resolve(R (T::*m)(void)) -> decltype(m) { return m; }

(Funciona para funciones de miembros; debe ser obvio cómo modificarlo para que funcione en funciones independientes, y debe poder proporcionar ambas versiones y el compilador seleccionará el más adecuado para usted).

Gracias a Miro Knejp por su sugerencia: ver también https://groups.google.com/a/isocpp.org/d/msg/std-discussion/rLVGeGUXsK0/IGj9dKmSyx4J .