c++ - Warum funktioniert diese Funktionszeigerzuweisung, wenn sie direkt, aber nicht mit dem bedingten Operator zugewiesen wird?




function pointers (2)

Dieses snippet gut mit gcc 9.1 kompilieren

#include <cctype>

int chr2fun(bool str2modus) {
    const bool STR2UP = true;
    int (*chr2fun)(int);

    if (str2modus == STR2UP) {
        chr2fun = std::toupper;
    } else {
        chr2fun = std::tolower;
    }
    chr2fun = (str2modus == STR2UP ? std::toupper : std::tolower);
}

Auf welcher Plattform und mit welchem ​​Compiler bekommen Sie den Fehler?

(Für dieses Beispiel wurden keine # include's verwendet, kompiliert unter MacOS10.14, Eclipse IDE, mit g ++, Optionen -O0 -g3 -Wall -c -fmessage-length = 0)

Angenommen, diese Variablendeklaration:

int (*fun)(int);

Dies kann nicht mit "ungültiger Überladung von std :: toupper und std :: tolower" kompiliert werden.

fun = (1 ? std::toupper : std::tolower);   // ERROR, invalid overload

Und das kompiliert OK:

if (1) {
    fun = std::toupper;   // OK
}
else {
    fun = std::tolower;   // OK
}

Im ersten Fall sperrt sich der Compiler, bevor er überhaupt zur Aufgabe kommt. Ein vereinfachter Ausdruck:

(true ? std::toupper : std::tolower)

Kompiliert nicht, wenn mehrere Überladungen von toupper / tolower vorhanden sind. Dies liegt daran, dass der Rückgabetyp des ternären Operators ausschließlich auf der Grundlage der Typen des 2. und 3. Arguments festgelegt werden muss, ohne jemals den Kontext zu betrachten, in dem das Ergebnis verwendet wird.

Komisch genug, auch wenn eines dieser Argumente keine überladene Funktion ist, ist das immer noch nicht genug. Die Gründe dafür sind weniger offensichtlich und haben mehr mit den Regeln für die Überlastungsauflösung 1 zu tun und wo sie gelten. Eine Besetzung ist genau eine von sieben Möglichkeiten, um sie auszulösen, und die Bestimmung des Zieltyps der ternären Operatoren selbst nicht.

Bei direkter Zuweisung muss die rechte Zuweisung mit der linken übereinstimmen, sodass keine Mehrdeutigkeit besteht.

Wie von @Caleth 16.5.4.2.1.6 , weist dieser Code gemäß 16.5.4.2.1.6 nicht angegebenes Verhalten auf.

1 Die C ++ - Referenz enthält einen falschen C ++ - Standardabsatz. [over.over] ist eigentlich 12.4.





overloading