Оператор bool () преобразован в std :: string и конфликтует с оператором std :: string () - PullRequest
4 голосов
/ 19 февраля 2010

Как оператор bool () может вызвать ошибку при объявлении оператора std :: string в классе, а также в качестве неявного преобразования в строку отдельно?

#include <iostream>
#include <string>
using namespace std;

class Test {
public:
    operator std::string() { cout << "op string" << endl; return "whatever";}
    operator bool() { cout << "op bool" << endl; return true;}
};

int main(int argc, char *argv[]) {
    string s;
    Test t;
    s = t;
}

Ответы [ 3 ]

8 голосов
/ 19 февраля 2010

Проблема, с которой вы сталкиваетесь (помимо operator std::string() возврата bool), заключается в том, что неявные преобразования инициируются, когда вы хотите, а когда нет.

Когда компилятор видит s = t, он определяет следующие потенциальные совпадения std::operator=:

// using std::string for compactness instead of the full template
std::string::operator=( std::string const & ); 
std::string::operator=( char );

Теперь t не является ни одним из них, поэтому он пытается преобразовать его во что-то подходящее и находит два пути: преобразовать в bool, который может быть повышен до char, или преобразовать в std::string напрямую. Компилятор не может действительно решить и сдается.

Это одна из причин, по которой вы хотите избежать предоставления множества различных операторов преобразования. Все, что может быть неявно вызвано компилятором, будет в конечном итоге вызвано, когда вы не думаете, что это должно.

Эта статья специально посвящена этой проблеме. Предложение вместо предоставления преобразования в bool, обеспечивает преобразование в функцию-член

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

Если экземпляр этого класса используется внутри условия (if (testable())), компилятор попытается преобразовать в bool_type, который можно использовать в условии.

EDIT

После комментария о том, как код является более сложным с этим решением, вы всегда можете предоставить его как обычную небольшую утилиту. Как только вы предоставите первую часть кода, сложность будет заключена в заголовок.

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

Ваш класс теперь стал намного проще и сам по себе читаем (выбирая подходящие имена для функций и типов):

// each class with conversion
class testable {
public:
   operator bool_type() {
      return safe_bool(true);
   }
};

Только если читатель заинтересован в том, чтобы узнать, как реализована идиома safe_bool, и прочитает заголовок, который он заполняет, столкнется со сложностью (которую можно объяснить в комментариях)

4 голосов
/ 19 февраля 2010

Ваш оператор std :: string () должен возвращать строку, а не bool.

1 голос
/ 19 февраля 2010

Как правильно указывает Дэвид Родригес, bool можно повысить до char, и вы получите неоднозначную перегрузку.

В stl создание тестируемого класса обычно выполняется путем преобразования в void *, например. когда вы делаете

while (istream.getline()) {
}

Условие цикла разрешается в ложь, потому что istream возвращает NULL в его операторе void *.

Некоторые люди утверждают, что это не то хорошее решение, как теоретически можно было бы сделать

void* streamptr = istream;
delete streamptr;

Но, по моему мнению, если кто-то начнет удалять подобные указатели ... его нельзя допускать рядом с кодом stl (или C ++ в этом отношении).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...