c++ - Verhindert, dass die Funktion const std:: string & 0 akzeptiert




implicit-conversion (2)

Der Grund, warum std::string(0) gültig ist, ist, dass 0 eine Nullzeiger-Konstante ist. Es entspricht also dem Konstruktor, der einen Zeiger nimmt. Dann läuft es unter der Voraussetzung, dass man keinen Nullzeiger an std::string darf. Nur das Literal 0 würde als Nullzeiger-Konstante interpretiert, wenn es sich um einen Laufzeitwert in einem int würde, hätte man dieses Problem nicht (da die Überladungsauflösung stattdessen nach einer int Konvertierung suchen würde). Auch Literal 1 kein Problem, da 1 keine Nullzeiger-Konstante ist.

Da es sich um ein Kompilierungsproblem handelt (buchstäblich ungültige Werte), können Sie es zur Kompilierungszeit abfangen. Fügen Sie eine Überladung dieses Formulars hinzu:

void operator[](std::nullptr_t) = delete;

std::nullptr_t ist der Typ von nullptr . Und es wird mit jeder Nullzeiger-Konstante übereinstimmen, sei es 0 , 0ULL oder nullptr . Und da die Funktion gelöscht wird, verursacht sie während der Überladungsauflösung einen Kompilierungszeitfehler.

Mehr als tausend Worte:

#include<string>
#include<iostream>

class SayWhat {
    public:
    SayWhat& operator[](const std::string& s) {
        std::cout<<"here\n"; // To make sure we fail on function entry
        std::cout<<s<<"\n";
        return *this;
    }
};

int main() {
    SayWhat ohNo;
    // ohNo[1]; // Does not compile. Logic prevails.
    ohNo[0]; // you didn't! this compiles.
    return 0;
}

Der Compiler beschwert sich nicht, wenn er die Zahl 0 an den Klammeroperator übergibt, der eine Zeichenfolge akzeptiert. Stattdessen wird dies kompiliert und schlägt fehl, bevor die Methode aufgerufen wird:

terminate called after throwing an instance of 'std::logic_error'
  what():  basic_string::_S_construct null not valid

Als Referenz:

> g++ -std=c++17 -O3 -Wall -Werror -pedantic test.cpp -o test && ./test
> g++ --version
gcc version 7.3.1 20180303 (Red Hat 7.3.1-5) (GCC)

Meine Vermutung

Der Compiler verwendet implizit den Konstruktor std::string(0) , um die Methode einzugeben. Dies führt ohne guten Grund zu demselben Problem (googeln Sie den obigen Fehler).

Frage

Gibt es eine Möglichkeit, dies auf der Klassenseite zu beheben, sodass der API-Benutzer dies nicht spürt und der Fehler beim Kompilieren erkannt wird?

Hinzufügen einer Überladung

void operator[](size_t t) {
    throw std::runtime_error("don't");
}

ist keine gute lösung.


Eine Möglichkeit besteht darin, eine private Überladung von operator[]() zu deklarieren, die ein integrales Argument akzeptiert und nicht definiert.

Diese Option funktioniert mit allen C ++ - Standards (ab 1998), im Gegensatz zu Optionen wie void operator[](std::nullptr_t) = delete die ab C ++ 11 gültig sind.

Wenn Sie den operator[]() einem private Mitglied machen, wird in Ihrem Beispiel ohNo[0] ein diagnostizierbarer Fehler verursacht, es sei denn, dieser Ausdruck wird von einer Mitgliedsfunktion oder einem friend der Klasse verwendet.

Wenn dieser Ausdruck von einer Mitgliedsfunktion oder einem friend der Klasse verwendet wird, wird der Code kompiliert, aber da die Funktion nicht definiert ist, schlägt der Build im Allgemeinen fehl (z. B. ein Linker-Fehler aufgrund einer undefinierten Funktion).





implicit-conversion