Vaut 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 en passant le numéro 0 à l'opérateur de parenthèse 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)
Ma conjecture
Le compilateur utilise implicitement le std::string(0)
constructeur pour entrer la méthode, ce qui génère le même problème (google l'erreur ci-dessus) sans raison valable.
Question
Existe-t-il un moyen 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?
Autrement dit, ajouter une surcharge
void operator[](size_t t) {
throw std::runtime_error("don't");
}
n'est pas une bonne solution.
c++
string
std
implicit-conversion
kabanus
la source
la source
operator[]()
qui accepte unint
argument et ne le définissez pas.Réponses:
La raison
std::string(0)
est valable, est due à0
être une constante de pointeur nul. Donc 0 correspond au constructeur de chaîne prenant un pointeur. Ensuite, le code va à l'encontre de la condition préalable à laquelle on ne peut pas passer un pointeur nulstd::string
.Seul le littéral
0
serait interprété comme une constante de pointeur nul, s'il s'agissait d'une valeur d'exécution dans un,int
vous n'auriez pas ce problème (car alors la résolution de surcharge chercherait uneint
conversion à la place). Le littéral n'est pas non plus1
un problème, car il1
ne s'agit pas d'une constante de pointeur nul.Puisqu'il s'agit d'un problème de temps de compilation (valeurs littérales invalides), vous pouvez l'attraper au moment de la compilation. Ajoutez une surcharge de ce formulaire:
std::nullptr_t
est le type denullptr
. Et il correspondra une constante de pointeur NULL, que ce soit0
,0ULL
ounullptr
. Et puisque la fonction est supprimée, elle provoquera une erreur de temps de compilation pendant la résolution de surcharge.la source
std::string
constructeur de n'est pas autorisée par la norme C ++. C'est un comportement indéfini, donc MSVC peut faire ce qu'il veut (comme lever une exception).Une option consiste à déclarer une
private
surchargeoperator[]()
qui accepte un argument intégral et à ne pas le définir.Cette option fonctionnera avec toutes les normes C ++ (à partir de 1998), contrairement aux options comme celles
void operator[](std::nullptr_t) = delete
qui sont valides à partir de C ++ 11.La création d'
operator[]()
unprivate
membre entraînera une erreur diagnostiquable sur votre exempleohNo[0]
, sauf si cette expression est utilisée par une fonction membre oufriend
de la classe.Si cette expression est utilisée à partir d'une fonction membre ou
friend
de la classe, le code sera compilé mais - puisque la fonction n'est pas définie - généralement la construction échouera (par exemple une erreur de l'éditeur de liens due à une fonction non définie).la source