c++ - Empêche la fonction de prendre const std:: string & d'accepter 0




implicit-conversion (2)

La raison pour laquelle std::string(0) est valide est due au fait que 0 est une constante de pointeur nulle. Donc, cela correspond au constructeur prenant un pointeur. Ensuite, il ne respecte pas la condition préalable selon laquelle il est interdit de passer un pointeur null à std::string . Seul le littéral 0 serait interprété comme une constante de pointeur nulle. S'il s'agissait d'une valeur d'exécution dans un int vous n'auriez pas ce problème (car la résolution de la surcharge chercherait plutôt une conversion int ). Le littéral 1 n'est pas non plus un problème, car 1 n'est pas une constante de pointeur nulle.

Puisqu'il s'agit d'un problème de compilation (valeurs non valides littérales), vous pouvez le résoudre au moment de la compilation. Ajouter une surcharge de ce formulaire:

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

std::nullptr_t est le type de nullptr . Et elle correspondra à toute constante de pointeur nulle, 0 , 0ULL ou nullptr . Et puisque la fonction est supprimée, cela entraînera une erreur de compilation lors de la résolution de la surcharge.

Mille mille mots:

#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;
}

Le compilateur ne se plaint pas lorsqu'il passe le nombre 0 à l'opérateur du crochet acceptant une chaîne. Au lieu de cela, cela compile et échoue avant l'entrée dans la méthode avec:

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

Pour référence:

> 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)

À mon avis

Le compilateur utilise implicitement le constructeur std::string(0) pour entrer dans la méthode, ce qui pose le même problème (google l'erreur ci-dessus) sans raison valable.

Question

Est-il possible de résoudre ce problème côté classe afin que l'utilisateur de l'API ne le ressente pas et que l'erreur soit détectée au moment de la compilation?

C’est-à-dire ajouter une surcharge

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

n'est pas une bonne solution.


Une option consiste à déclarer une surcharge private d' operator[]() qui accepte un argument intégral, sans le définir.

Cette option fonctionnera avec toutes les normes C ++ (1998), contrairement aux options telles que void operator[](std::nullptr_t) = delete qui sont valides à partir de C ++ 11.

Faire de l' operator[]() un membre private provoquera une erreur ohNo[0] diagnostiquée sur votre exemple ohNo[0] , à moins que cette expression ne soit utilisée par une fonction membre ou un friend de la classe.

Si cette expression est utilisée à partir d'une fonction membre ou d'un friend de la classe, le code se compilera mais, puisque la fonction n'est pas définie, la construction échouera généralement (par exemple, une erreur de l'éditeur de liens due à une fonction non définie).





implicit-conversion