2010-07-27 3 views
5
int foo(int){  
    ... 
} 

¿Alguna idea?En C++, en la definición de funciones, los identificadores de argumento son opcionales. ¿En qué escenario esta característica podría ser útil?

+1

Nota, esto solo es válido para C++ y no para C. Menciono esto por la etiqueta C. – quinmars

+0

gracias, utilicé la etiqueta c para subrayar la diferencia. –

+0

No es así como se usan las etiquetas. Si busco todos los temas etiquetados con "C", no espero encontrar temas que no sean relevantes para C. Eso no tiene sentido, así que eliminé la etiqueta. –

Respuesta

7

Un caso en el que se define una función, pero no nombra el parámetro se da en la de Scott Meyers "Eficaz C++, 3ª edición", artículo 47:

template<typename IterT, typename DistT>   
void doAdvance(IterT& iter, DistT d,    
       std::random_access_iterator_tag) 
{ 
    iter += d; 
} 

se utiliza en:

template<typename IterT, typename DistT> 
void advance(IterT& iter, DistT d) 
{ 
    doAdvance(iter, d, 
      typename std::iterator_traits<IterT>::iterator_category()); 
} 

Básicamente, el tercer parámetro en doAdvance es un tipo no acompañado por un nombre de variable, es decir, es un parámetro sin nombre. Tener un parámetro sin nombre no es un problema, ya que ese argumento solo se usa durante la resolución de qué función sobrecargada usar. Discuto estos temas en this SO relacionada pregunta.

11

Cuando no está realmente usando el parámetro en la función, pero no quiere romper la firma del método público.

+0

Alexandros ha dado un [muy buen ejemplo] (http://stackoverflow.com/questions/3348223/in-c-in-the-definition-of-functions-the-argument-identifiers-are-optional-in/3348345 # 3348345) para explicar por qué no te importa el objeto real, excepto que está ahí. – sbi

0

Creo que quiere decir en la declaración de funciones. En realidad, también puede omitir el nombre del identificador en la definición de funciones, pero esto causará un error de compilación si se usa el parámetro, que es probable que suceda.

3

En algunos casos, los compiladores advertirán de los parámetros no utilizados, a menos que deje el nombre del identificador como se muestra. También es potencialmente útil mostrar que un parámetro no se usa. Aparte de eso, no tengo idea. Ciertamente no puedes dejar el identificador desactivado si usas el parámetro.

4

Así es como el compilador diferencia los operadores de incremento de prefijo y prefijo: X operador ++() es prefijo, X operador ++ (int) es postfijo.

Como int nunca se utiliza realmente en el operador postfix, no hay ninguna razón para darle un nombre. Por lo general, esta es la razón por la que obtiene parámetros sin nombre, para sobrecargar una función u operador para significar dos cosas ligeramente diferentes. Este es un truco común en la metaprogramación de plantillas como se usa en Loki y Boost.

+0

Es posible que desee dejar en claro al OP que la razón por la que funciona es debido a la resolución de sobrecarga ... aunque supongo que acabo de hacerlo. –

+0

No, no lo es. Estas son firmas diferentes, es decir, los tipos de argumentos son diferentes. Lo que el OP está preguntando es sobre omitir el identificador de algún parámetro. – Juliano

+0

¿Eh? Joel está mostrando cómo un compilador puede discriminar entre ++ i y i ++ utilizando un parámetro sin nombre. ¿De qué estás hablando? –

1

Lo haces cuando estás implementando una función de alguna firma, no necesitas el parámetro (bastante común en las jerarquías detrás de un resumen) y necesitas compilar sin advertencias. Dado que todos los proyectos se deben configurar para que se rompan cuando hay una advertencia, y esto viene MUCHO en OOP/GP, es algo muy, muy común de hacer. De hecho, es tan común que muchas bibliotecas tengan una macro mylibUNUSED() para una mejor legibilidad.

1

Tenga en cuenta que el hecho de que el compilador no se preocupa por el nombre de parámetro real viene del hecho de que se puede utilizar diferentes nombres de los parámetros para una función (plantilla) declaración 's que para su definición.

Esto es útil cuando tiene una biblioteca que envía como encabezados y como archivo lib y todos los que usan su API no tendrán que volver a compilar todo solo porque, dentro de la biblioteca, cambian los nombres de algunos parámetro (s). (Probablemente tiene que haber estado en un proyecto multi-MLoC C++ para apreciarlo.)

2

Los parámetros adicionales pueden ser utilizados por SFINAE, para resolución de sobrecarga o despacho dependiendo de las propiedades de tipo.

#include <boost/utility/enable_if.hpp> 
#include <boost/type_traits.hpp> 
#include <boost/call_traits.hpp> 
#include <iostream> 
#include <string> 

// use SFINAE enable this function for numerical types only 
template <class T> 
double foo(T t, typename 
       boost::enable_if<boost::is_floating_point<T> >:: 
       type* dummy = 0) { 
    double x = static_cast<double>(t); 
    return x; 
} 

// use extra parameter for overload resolution 
struct PlanA {}; 
struct PlanB {}; 

void bar(const PlanA&) { 
    std::cout << "using plan A...\n"; 
} 

void bar(const PlanB&) { 
    std::cout << "using plan B...\n"; 
} 

// use type traits to choose which function to call 
template <typename T> 
double fooBar(T t) { 
    return dispatch(t, boost::is_convertible<T, double>()); 
} 

double dispatch(double t, const boost::true_type&) { 
    std::cout << "convertible to double\n"; 
    return t+0.1; 
} 

template <typename T> 
double dispatch(const T&, const boost::false_type&) { 
    std::cout << "not convertible to double\n"; 
    return 0.0; 
} 


int main() { 

    foo(1.0); 
    // foo(1); won't compile 

    bar(PlanA()); 
    bar(PlanB()); 

    std::string name = "John Dow"; 

    fooBar(1.0); 
    fooBar(name); 
} 
Cuestiones relacionadas