Constructor predeterminado con corchetes vacíos

6 minutos de lectura

Constructor predeterminado con corchetes vacios
Martín Beckett

¿Hay alguna buena razón por la que un conjunto vacío de corchetes (paréntesis) no sea válido para llamar al constructor predeterminado en C++?

MyObject  object;  // ok - default ctor
MyObject  object(blah); // ok

MyObject  object();  // error

Parece que escribo “()” automáticamente cada vez. ¿Hay alguna buena razón por la que esto no esté permitido?

  • Alguien debería pensar en un mejor título para esto, pero no puedo pensar en cuál sería. Al menos deletree “constructor” para ayudar a los motores de búsqueda.

    – Adán Mitz

    8 de octubre de 2008 a las 5:18

  • Y este es solo otro buen ejemplo donde C++ es sensible al contexto. El código de ejemplo en la pregunta también fallaría si blah sería una clase.

    – Alberto

    27 de agosto de 2010 a las 21:03

  • Una cosa que noté es que si solo tengo el constructor predeterminado, el compilador no da ningún error si uso () p.ej MyObject object funciona como siempre y MyObject object() no da ningun error! ¿Podría alguien explicar por qué? Quiero decir que no he definido la función en mi main… así que debería dar un error, ¿verdad? ¡Gracias por adelantado!

    – Milán

    12 de noviembre de 2020 a las 0:04

Constructor predeterminado con corchetes vacios
Constantino

El análisis más desconcertante

Esto está relacionado con lo que se conoce como “el análisis más desconcertante de C++”. Básicamente, cualquier cosa que el compilador pueda interpretar como una declaración de función se interpretará como una declaración de función.

Otro ejemplo del mismo problema:

std::ifstream ifs("file.txt");
std::vector<T> v(std::istream_iterator<T>(ifs), std::istream_iterator<T>());

v se interpreta como una declaración de función con 2 parámetros.

La solución es agregar otro par de paréntesis:

std::vector<T> v((std::istream_iterator<T>(ifs)), std::istream_iterator<T>());

O, si tiene C++ 11 e inicialización de lista (también conocida como inicialización uniforme) disponibles:

std::vector<T> v{std::istream_iterator<T>{ifs}, std::istream_iterator<T>{}};

Con esto, no hay forma de que pueda interpretarse como una declaración de función.

  • Nitpick: tú lata declarar funciones dentro de funciones. Se llama funciones locales en C, y al menos extern "C" foo();-style también está permitido en C++.

    – Marc Mutz – mmutz

    8 de agosto de 2009 a las 10:20

  • ¿Cómo se puede interpretar eso como una función?

    – Casebash

    29 de octubre de 2010 a las 1:00

  • @Casebash, std::vector es tipo de retorno; v es el nombre de la función; ( abre la lista de argumentos formales; std::istream_iterator es tipo de primer argumento; ifs es el nombre del primer argumento, () alrededor ifs son efectivamente ignorados; segundo std::istream_iterator es el tipo de segundo argumento, que no tiene nombre, () a su alrededor también se ignoran; ‘);’ cierra la lista de argumentos y la declaración de funciones.

    – Constantino

    30 de octubre de 2010 a las 7:31


  • Existe una ambigüedad en la gramática que involucra sentencias de expresión y declaraciones: una sentencia de expresión con una conversión de tipo explícita de estilo de función como su subexpresión más a la izquierda puede ser indistinguible de una declaración donde el primer declarador comienza con un (. En esos casos, la sentencia es una declaración (C++ ISO/IEC (2003) 6.8.1)

    – bartolo-otrit

    28 de septiembre de 2012 a las 9:12

  • @Constantin, los paréntesis después del segundo argumento no se ignoran. El segundo parámetro no es un std::istream_iterator pero un puntero/referencia a una función que no toma argumentos y devuelve un istream_iterator.

    – CTMacUsuario

    15 de febrero de 2014 a las 0:25

1647653827 724 Constructor predeterminado con corchetes vacios
1800 INFORMACIÓN

Porque se trata como la declaración de una función:

int MyFunction(); // clearly a function
MyObject object(); // also a function declaration

  • Pero debería dar un error, ¿verdad? Porque no hemos definido el object() función verdad? ¿Podría dar más detalles sobre eso? Estoy confundido ahora mismo. ¡Muchas gracias de antemano!

    – Milán

    12 de noviembre de 2020 a las 0:07

  • En una nota al margen, en mi mainincluso probé estos: any_variable_name random_function_name() p.ej int func1() , double func2(), void func3(), etc. y todos ellos funcionan, es decir, ¡mi programa se compila sin ningún error! Sin embargo, no he definido ninguna de esas funciones, por lo que debería recibir errores, ¿no?

    – Milán

    12 de noviembre de 2020 a las 0:13


  • @Milan Esperaría errores de vinculación si realmente intentara llamar a esas funciones. De lo contrario, son solo declaraciones.

    – 1800 INFORMACIÓN

    15 de noviembre de 2020 a las 22:31

La misma sintaxis se utiliza para la declaración de funciones, por ejemplo, la función objectsin tomar parámetros y volviendo MyObject

  • Gracias, no se me ocurriría declarar una función en medio de otro código. Pero supongo que es legal.

    – Martín Beckett

    7 oct 2008 a las 20:36

Porque el compilador piensa que es una declaración de una función que no toma argumentos y devuelve una instancia de MyObject.

También podría usar la forma de construcción más detallada:

MyObject object1 = MyObject();
MyObject object2 = MyObject(object1);

En C++ 0x esto también permite auto:

auto object1 = MyObject();
auto object2 = MyObject(object1);

  • Esto requiere un constructor de copias y es ineficiente.

    – Casebash

    29 de octubre de 2010 a las 1:01


  • @Casebash: el compilador probablemente sea lo suficientemente inteligente como para usar algunos RVO-como la optimización evita que sea ineficiente.

    – dalle

    29 de octubre de 2010 a las 11:23

  • “Probablemente” significa “Estoy suponiendo”. Con respecto a la optimización, la gente generalmente no quiere adivinar, sino que toma el camino explícito.

    – Stefan

    4 de noviembre de 2014 a las 14:35

  • @Stefan: No es necesario “adivinar”; la elisión de copia ocurrirá aquí en todos los principales compiladores y ese ha sido el caso durante más de una década. No es que este sea un buen código.

    – Carreras de ligereza en órbita

    25 de junio de 2015 a las 18:19


  • Como C++17 no hay copiar/mover, el comportamiento se define como idéntico a la inicialización directa

    –MM

    22 de febrero a las 23:45

1647653828 219 Constructor predeterminado con corchetes vacios
Negro

Supongo que el compilador no sabría si esta declaración:

objeto MiObjeto();

es una llamada de constructor o un prototipo de función que declara una función llamada objeto con tipo de retorno MiObjeto y sin parámetros.

  • Esto requiere un constructor de copias y es ineficiente.

    – Casebash

    29 de octubre de 2010 a las 1:01


  • @Casebash: el compilador probablemente sea lo suficientemente inteligente como para usar algunos RVO-como la optimización evita que sea ineficiente.

    – dalle

    29 de octubre de 2010 a las 11:23

  • “Probablemente” significa “Estoy suponiendo”. Con respecto a la optimización, la gente generalmente no quiere adivinar, sino que toma el camino explícito.

    – Stefan

    4 de noviembre de 2014 a las 14:35

  • @Stefan: No es necesario “adivinar”; la elisión de copia ocurrirá aquí en todos los principales compiladores y ese ha sido el caso durante más de una década. No es que este sea un buen código.

    – Carreras de ligereza en órbita

    25 de junio de 2015 a las 18:19


  • Como C++17 no hay copiar/mover, el comportamiento se define como idéntico a la inicialización directa

    –MM

    22 de febrero a las 23:45

1647653828 482 Constructor predeterminado con corchetes vacios
miguel rebabas

Como se mencionó muchas veces, es una declaración. Es así por compatibilidad con versiones anteriores. Una de las muchas áreas de C++ que son tontas/inconsistentes/dolorosas/falsas debido a su legado.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad