Le problème que vous rencontrez (en plus de operator std::string()
retournant un booléen) est que les conversions implicites se déclenchent quand vous voulez et quand vous ne le faites pas.
Lorsque le compilateur voit s = t
il identifie les std::operator=
potentiels matchs suivants:
// using std::string for compactness instead of the full template
std::string::operator=(std::string const &);
std::string::operator=(char);
Maintenant, t
est ni d'eux, donc il essaie de convertir à quelque chose qui peut s'adapter et trouve deux chemins: convertir en bool qui peut être promu à char
ou convertir en std::string
directement. Le compilateur ne peut pas vraiment décider et abandonne.
C'est l'une des raisons pour lesquelles vous voulez éviter de fournir plusieurs opérateurs de conversion différents. Tout ce qui peut être implicitement appelé par le compilateur sera éventuellement appelé quand vous ne le pensez pas.
Cette article traite spécifiquement de ce problème. La suggestion est au lieu de fournir une conversion à bool
, fournir une conversion à une fonction de membre
class testable {
typedef void (testable::*bool_type)();
void auxiliar_function_for_true_value() {}
public:
operator bool_type() const {
return condition() ? &testable::auxiliar_function_for_true_value : 0;
}
bool condition() const;
};
Si une instance de cette classe est utilisée dans une condition (if (testable())
) le compilateur va essayer de se convertir à l'bool_type
qui peut être utilisé dans un état.
EDIT:
Après le commentaire sur la façon dont le code est plus complexe avec cette solution, vous pouvez toujours fournir un petit utilitaire générique. Une fois que vous avez fourni la première partie du code, la complexité est encapsulée dans l'en-tête.
// utility header safe_bool.hpp
class safe_bool_t;
typedef void (safe_bool_t::*bool_type)();
inline bool_type safe_bool(bool);
class safe_bool_t {
void auxiliar_function_for_true_value() {}
friend bool_type safe_bool(bool);
};
inline bool_type safe_bool(bool)
{
return condition ? &safe_bool_t::auxiliar_function_for_true_value : 0;
}
Votre classe devient beaucoup plus simple, et il est lisible en lui-même (en choisissant des noms appropriés pour les fonctions et types):
// each class with conversion
class testable {
public:
operator bool_type() {
return safe_bool(true);
}
};
Seulement si le lecteur est intéressé à savoir comment la idiome safe_bool
est mis en œuvre et lit l'en-tête, ils remplissent être confrontés à la complexité (qui peut être expliqué dans les commentaires)
Si vous allez de l'avant et que vous utilisez 'namespace std;' pourquoi allez-vous préciser 'std :: string'? –