2012-04-02 25 views
22

Al desarrollar una aplicación, tuve el siguiente problema. Quería devolver un std::list<string> vacío cuando un puntero de función determinado era nulo, o el resultado de esa función en caso contrario. Esta es una versión simplificada de mi código:Ternary operator + C++ 11 constructor from initializer_list

typedef std::list<std::string> (*ParamGenerator)(); 

std::list<std::string> foo() { 
    /* ... */ 
    ParamGenerator generator = ...; 
    if(generator) 
     return generator(); 
    else 
     return {}; 
} 

Sin embargo, normalmente me gusta usar el ternario (?:) del operador en estos casos, así que traté de usarlo de esta manera (como es habitual):

return generator ? generator() : {}; 

Pero consiguió este error:

somefile.cpp:143:46: error: expected primary-expression before ‘{’ token 
somefile.cpp:143:46: error: expected ‘;’ before ‘{’ token 

¿esto significa que no puede utilizar el operador ternario para devolver los objetos creados utilizando su constructor de una initializer_list? ¿Hay alguna razón en particular para eso?

+1

Mi consejo sería: ** no hagas esto en absoluto **. Conviértalo en un algoritmo genérico que toma un iterador (cuyo tipo es un parámetro de plantilla), de modo que cuando se da cuenta de que 'std :: list' era una mala elección, puede cambiar a otra cosa de forma relativamente sencilla. –

+0

@JerryCoffin Probablemente tomaré ese consejo;). Me gustaría saber si es posible de todos modos (o por qué no es así, no se puede hacer). – mfontanini

+0

De acuerdo, es suficiente. Es una pregunta interesante (por la que he votado) aunque creo que la aplicación exacta probablemente no sea la mejor. –

Respuesta

15

estándar en 8.5.4.1: Lista-inicialización

Note: List-initialization can be used

  • as the initializer in a variable definition (8.5)
  • as the initializer in a new expression (5.3.4)
  • in a return statement (6.6.3)
  • as a function argument (5.2.2)
  • as a subscript (5.2.1)
  • as an argument to a constructor invocation (8.5, 5.2.3)
  • as an initializer for a non-static data member (9.2)
  • in a mem-initializer (12.6.2)
  • on the right-hand side of an assignment (5.17)

Nada de ellos es un operador ternario. El return 1?{}:{}; más minimalista tampoco es válido, lo que quiere es imposible.

Por supuesto, puede llamar explícitamente al constructor std::list<std::string>{}, pero recomendaría escribir el if - else -block como ya hizo.

+0

Genial, esa fue la justificación que estaba buscando. – mfontanini

3

Cuando hace {} el compilador no tiene conocimiento del tipo que está esperando, por lo que es simplemente una expresión sin sentido que el compilador no sabe qué hacer. Ambos lados del : se evalúan por separado, y solo entonces el compilador se queja si los tipos no coinciden. Me acaba de hacer esto: escribe

return generator ? generator() : std::list<std::string>(); 
2

Si realmente te gusta el operador ternario, se puede intentar algo como esto:

return generator ? generator() : decltype(generator()) { "default value", "generator was empry" };

que funcionará incluso si cambia los tipos de retorno más tarde.