una todas tipos tipo son simples referencia reales qué por paso parámetros parametros parametro parameter opcionales los llamar lenguaje las funciones funcion formales estructura enviar ejemplos dev define defecto declaracion con como argumentos c++ member-functions default-arguments

c++ - todas - ¿Es posible usar la función de llamada de miembro como argumento predeterminado?



tipos de parametros en c++ (3)

Aquí está mi código:

struct S { int f() { return 1; } int g(int arg = f()) { return arg; } }; int main() { S s; return s.g(); }

Esto no se compila con el error:

error: cannot call member function ''int S::f()'' without object

Intentar this->f() tampoco funciona, ya que no se puede usar en ese contexto.

¿Hay alguna manera de hacer que esto funcione, aún usando el argumento predeterminado?

Por supuesto, se puede evitar evitando los argumentos predeterminados:

int g(int arg) { return arg; } int g() { return g(f()); }

sin embargo, esto se vuelve detallado considerando que en el "código real" hay más parámetros antes de arg , y varias funciones siguiendo este patrón. (Y aún más feo si hubiera múltiples argumentos predeterminados en la función).

NÓTESE BIEN. Esta pregunta parece similar al principio, pero en realidad está preguntando cómo hacer un cierre, que es un problema diferente (y la solución vinculada no se aplica a mi situación).


Agrego otra respuesta, que es completamente diferente de la anterior y podría resolver su problema.
La idea es usar otra clase y la combinación correcta de constructores explícitos y no explícitos.
Sigue un mínimo, ejemplo de trabajo:

#include <functional> #include <iostream> template<class C, int(C::*M)()> struct Arg { std::function<int(C*)> fn; Arg(int i): fn{[i](C*){ return i; }} { } explicit Arg(): fn{[](C* c){ return (c->*M)(); }} { } }; struct S { int f() { return 1; } int h() { return 2; } void g(int arg0, Arg<S, &S::f> arg1 = Arg<S, &S::f>{}, Arg<S, &S::h> arg2 = Arg<S, &S::h>{}) { std::cout << "arguments" << std::endl; std::cout << "arg0: " << arg0 << std::endl; std::cout << "arg1: " << arg1.fn(this) << std::endl; std::cout << "arg2: " << arg2.fn(this) << std::endl; } }; int main() { S s{}; s.g(42, 41, 40); s.g(0); }

El ejemplo muestra cómo puede mezclar parámetros predeterminados y no predeterminados.
Es bastante sencillo modificarlo y dejar que g sea ​​una función con una lista de argumentos vacía, como en la pregunta original.
También estoy bastante seguro de que uno puede refinar el ejemplo y terminar con algo mejor que eso, de todos modos debería ser un buen punto de partida.

Sigue la solución aplicada al ejemplo original de la pregunta:

#include <functional> template<class C, int(C::*M)()> struct Arg { std::function<int(C*)> fn; Arg(int i): fn{[i](C*){ return i; }} { } explicit Arg(): fn{[](C* c){ return (c->*M)(); }} { } }; struct S { int f() { return 1; } int g(Arg<S, &S::f> arg = Arg<S, &S::f>{}) { return arg.fn(this); } }; int main() { S s{}; return s.g(); }

Y eso es todo, es posible hacerlo, incluso sin métodos static o variables globales.
Por supuesto, podemos usar nuestro esto de alguna manera. Se trata de doblar un poco el idioma ...


Si se le permite usar funciones experimentales de C ++ 17, puede usar std::optional desde la STL (consulte here para obtener más detalles).

En otros términos algo como:

int g(std::optional<int> oarg = std::optional<int>{}) { int arg = oarg ? *oarg : f(); // go further }

EDITAR

Como se sugiere en los comentarios, el código anterior debe ser lógicamente equivalente al siguiente:

int g(std::optional<int> oarg = std::optional<int>{}) { int arg = oarg.value_or(f()); // go further }

Este es un poco más legible (¿no es así?), Pero tenga en cuenta que se ejecuta f en cualquier caso.
Si esa función es costosa, tal vez no valga la pena.


Solo puedes usar miembros allí si son static . De un borrador de C ++ 11 (n3299), §8.3.6 / 9:

De manera similar, un miembro no estático no se usará en un argumento predeterminado, incluso si no se evalúa, a menos que aparezca como la expresión-id de una expresión de acceso de miembro de clase (5.2.5) o a menos que se use para formar un puntero al miembro (5.3.1).

Por ejemplo, esto funciona:

struct S { static int f() { return 1; } int g(int arg = f()) { return arg; } }; int main() { S s; return s.g(); }

Esto también funciona (creo que eso es lo que significa la primera expresión):

struct S { int f() { return 42; } int g(int arg); }; static S global; int S::g(int arg = global.f()) { return arg; } int main() { S s; return s.g(); }

En cuanto a this , de hecho no está permitido (§8.3.6 / 8):

La palabra clave this no se utilizará en un argumento predeterminado de una función miembro.

La página de argumentos por defecto en cppreference.com tiene muchos detalles sobre el tema, puede ser bastante complejo.