2012-04-02 11 views
22

Während der Entwicklung einer Anwendung hatte ich das folgende Problem. Ich wollte eine leere std::list<string> zurückgeben, wenn ein gegebener Funktionszeiger Null war, oder das Ergebnis dieser Funktion andernfalls. Dies ist eine vereinfachte Version meiner Code:Ternärer Operator + C++ 11 Konstruktor aus Initialisiererliste

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

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

Allerdings habe ich in der Regel die ternäre verwenden möchten (?:) Betreiber in diesen Fällen, also versuchte ich es auf diese Weise mit (wie üblich):

return generator ? generator() : {}; 

Aber habe diesen Fehler:

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

bedeutet das kann ich nicht den ternären Operator verwenden, um Objekte zurück von einem initializer_list ihren Konstruktor erstellt? Gibt es dafür einen besonderen Grund?

+1

Mein Rat wäre: ** Tun Sie das überhaupt nicht **. Machen Sie es zu einem generischen Algorithmus, der einen Iterator (dessen Typ ein Template-Parameter ist) verwendet. Wenn Sie also feststellen, dass 'std :: list' eine schlechte Wahl ist, können Sie relativ problemlos zu etwas anderem wechseln. –

+0

@JerryCoffin Ich werde wahrscheinlich diesen Rat nehmen;). Ich würde gerne wissen, ob es überhaupt möglich ist (oder warum es nicht möglich ist). – mfontanini

+0

Okay, fair genug. Es ist eine interessante Frage (für die ich mich entschieden habe), obwohl ich denke, dass die genaue Anwendung wahrscheinlich nicht die beste ist. –

Antwort

15

Norm schreibt in 8.5.4.1: List-Initialisierung

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)

Nichts davon ist ein ternärer Operator. Das minimalistischere return 1?{}:{}; ist auch ungültig, was Sie wollen, ist unmöglich.

Natürlich können Sie explizit den Konstruktor std::list<std::string>{} aufrufen, aber ich würde empfehlen, den if - else-Block wie Sie bereits schreiben.

+0

Großartig, das war die Rechtfertigung, nach der ich gesucht habe. – mfontanini

3

Wenn Sie {} tun, hat der Compiler keine Kenntnis von dem Typ, den Sie erwarten, also ist es nur ein bedeutungsloser Ausdruck, dass der Compiler nicht weiß, was er damit machen soll. Beide Seiten der : werden separat ausgewertet, und nur dann wird der Compiler beschweren, wenn die Typen nicht übereinstimmen. Ich würde dies nur tun:

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

Wenn Sie wirklich, wie der ternäre Operator, können Sie so etwas wie dies versuchen:

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

es wird auch funktionieren, wenn Sie die Rückgabetypen später ändern.