¿Cómo asigno un alias a un nombre de función en C ++?

100

Es fácil crear un nuevo nombre para un tipo, una variable o un espacio de nombres. Pero, ¿cómo asigno un nuevo nombre a una función? Por ejemplo, quiero usar el nombre hollerpara printf. #definir es obvio ... ¿de otra manera?

Soluciones:

  1. #define holler printf
  2. void (*p)() = fn; //function pointer
  3. void (&r)() = fn; //function reference
  4. inline void g(){ f(); }
Agnel Kurian
fuente
Gracias a todos ustedes. A mis colegas les encantará verlo void (&NewName)(some_vector&, float, float, float, float) = OldName;en mi próxima visita.
Agnel Kurian
19
no tanto como les encantará verte usar nombres aleatorios para funciones de biblioteca estándar.
jalf
2
No estoy jugando con printfesto. Eso fue solo un ejemplo. El problema aquí tiene más que ver con las limitaciones del inglés que con cualquier otra cosa. Tengo una sola función que sirve al propósito A y al propósito B, pero simplemente no puedo encontrar un nombre único que sirva para ambos propósitos aquí.
Agnel Kurian
2
@Neil, precisamente. T &a = b;crea un nuevo nombre para b. typedefpara tipos y namespace A=B;espacios de nombres.
Agnel Kurian
2
Hay using BaseClass::BaseClassMethod, y hay using AliasType = Type;, e incluso hay namespace AliasNamespace = Namespace;. Lo que nos falta esusing AliasFunction = Function;
anton_rh

Respuestas:

114

Hay diferentes enfoques:

  • Con C ++ 11 con funciones no sobrecargadas sin plantilla, simplemente puede usar:

    const auto& new_fn_name = old_fn_name;
  • Si esta función tiene múltiples sobrecargas, debe usar static_cast:

    const auto& new_fn_name = static_cast<OVERLOADED_FN_TYPE>(old_fn_name);

    Ejemplo: hay dos sobrecargas de funciones std::stoi

    int stoi (const string&, size_t*, int);
    int stoi (const wstring&, size_t*, int);

    Si desea crear un alias para la primera versión, debe usar lo siguiente:

    const auto& new_fn_name = static_cast<int(*)(const string&, size_t*, int)>(std::stoi);

    Nota: no hay forma de crear un alias para la función sobrecargada de modo que todas sus versiones sobrecargadas funcionen, por lo que siempre debe especificar qué sobrecarga de función exacta desea.

  • Con C ++ 14 puede ir aún más lejos con constexprlas variables de plantilla. Eso le permite alias funciones con plantilla:

    template<typename T>
    constexpr void old_function(/* args */);
    
    template<typename T>
    constexpr auto alias_to_old = old_function<T>;
  • Además, comenzando con C ++ 11 tiene una función llamada std::mem_fnque permite alias funciones miembro. Vea el siguiente ejemplo:

    struct A {
       void f(int i) {
          std::cout << "Argument: " << i << '\n';
       }
    };
    
    
    A a;
    
    auto greet = std::mem_fn(&A::f); // alias to member function
    // prints "Argument: 5"
    greet(a, 5); // you should provide an object each time you use this alias
    
    // if you want to bind an object permanently use `std::bind`
    greet_a = std::bind(greet, a, std::placeholders::_1);
    greet_a(3); // equivalent to greet(a, 3) => a.f(3);
sasha.sochka
fuente
1
Excelente, ¿qué tal C ++ 98? Tengo una clase con 2 sobrecargas de "reinicio" que se utilizan para configurar y reiniciar. Internamente, no hay problema. Para los usuarios externos, quería establecer un alias como "establecer", por lo que es intuitivo para el contexto (establezca una configuración predeterminada, clear () 'd, etc .; restablecer el objeto de trabajo). Métodos de clase: (1) "void (& set) (const string &, const bool, const bool);" (2) void (& set) (const string &, const int, const bool); 2 "restablecer" con las firmas correspondientes hacen el trabajo. Como tengo la firma en la declaración de clase, ¿puedo simplemente inicializar la clase,: set (reset), set (reset). Si no es así, ¿funcionará su ejemplo explícito de static_cast?
Luv2code
8
Parece haber un problema con el constexprenfoque de variables de plantilla: el alias no puede realizar una deducción de tipo. El compilador requiere que proporcione una lista de parámetros de plantilla (estoy escribiendo una función de plantilla variable): no se puede hacer referencia a la plantilla de variable `alias_to_old 'sin una lista de argumentos de plantilla
user69818
1
constexpr auto new_fn_name = old_fn_namefunciona en C ++ 11 (al menos en gcc 4.9.2) y es mejor que colocar &. No requiere que la llamada se realice siempre a través de un puntero y, por lo tanto, permite que la función esté en línea en lugar de la llamada.
ony
Con lambdas genéricas de C ++ 14, pude hacer lo siguiente, que también debería funcionar cuando la función de destino tiene múltiples sobrecargas: constexpr auto holler = [] ( auto &&...args ) { return printf( std::forward<decltype(args)>( args )... ); };
Anthony Hall
1
Usar nostd::mem_fn es un alias ya que realiza mucha más magia detrás del sentido.
cgsdfc
35

Puede crear un puntero de función o una referencia de función:

void fn()
{
}

//...

void (*p)() = fn;//function pointer
void (&r)() = fn;//function reference
Brian R. Bondy
fuente
2
Esto se lleva la palma. No sabía nada de referencias a funciones.
Agnel Kurian
@Vulcan: Son casi iguales en que puede llamar a ambos con la misma sintaxis, pero sus direcciones son un poco diferentes. r no ocupa su propio espacio de memoria con una dirección.
Brian R. Bondy
1
¿Cómo llamarías fn, usando el alias? ¿Puede explicar el puntero de función y la referencia de función? ¿En qué se diferencian? ¿Son iguales aquí?
ma11hew28
1
@ Matt, lo llamas exactamente como llamarías fn. r();
Agnel Kurian
¿Cómo harías esto para un método de instancia? EDITAR: esto parece compilar:void (&r)() = this->fn;
Sam
21
typedef int (*printf_alias)(const char*, ...);
printf_alias holler = std::printf;

Debería estar bien.

jer
fuente
¿No está printf en el espacio de nombres global?
Agnel Kurian
3
es global si incluyó <stdio.h>, pero en std si incluyó <cstdio>
Injektilo
@einpoklum: No hay nada de malo con decltype , pero la respuesta es de 2010. En ese entonces no existía decltypecomo se introdujo en c ++ 11. Además, este también debe trabajar con el bueno de C. llanura
Phidelux
10

int (*holler)(const char*, ...) = std::printf;

MSalters
fuente
7

Utilice una envoltura en línea. Obtiene ambas API, pero conserva la implementación única.

Juan
fuente
3

De fluentcpp : ALIAS_TEMPLATE_FUNCTION (f, g)

#define ALIAS_TEMPLATE_FUNCTION(highLevelF, lowLevelF) \
template<typename... Args> \
inline auto highLevelF(Args&&... args) -> decltype(lowLevelF(std::forward<Args>(args)...)) \
{ \
    return lowLevelF(std::forward<Args>(args)...); \
}
pez vela009
fuente
0

Vale la pena mencionar aquí, en mi opinión, que si bien la pregunta original (y las excelentes respuestas) son definitivamente útiles si desea cambiar el nombre de una función (¡hay buenas razones para hacerlo!), Si todo lo que desea hacer es eliminar un espacio de nombres profundo, pero mantener el nombre, existe la usingpalabra clave para esto:

namespace deep {
  namespace naming {
    namespace convention {
      void myFunction(int a, char b) {}
    }
  }
}
int main(void){
  // A pain to write it all out every time
  deep::naming::convention::myFunction(5, 'c');

  // Using keyword can be done this way
  using deep::naming::convention::myFunction;
  myFunction(5, 'c');  // Same as above
}

Esto también tiene la ventaja de que se limita a un ámbito, aunque siempre se puede utilizar en el nivel superior de un archivo. A menudo utilizo esto para couty endlasí que no necesito llevar en todas stdcon el clásico using namespace std;en la parte superior de un archivo, pero también es útil si usted está usando algo comostd::this_thread::sleep_for() una gran cantidad en un solo archivo o función, pero no en todas partes, y ninguna otra función del espacio de nombres. Como siempre, se desaconseja usarlo en archivos .h, o contaminará el espacio de nombres global.

Esto no es lo mismo que el "cambio de nombre" anterior, pero a menudo es lo que realmente se desea.

Kevin Anderson
fuente
0

Con lambdas genéricas C ++ 14, pude hacer lo siguiente, que también debería funcionar cuando la función de destino tiene múltiples sobrecargas:

constexpr auto holler = [] ( auto &&...args ) {
        return printf( std::forward<decltype(args)>( args )... );
    };
Anthony Hall
fuente