Страницы

Поиск по вопросам

воскресенье, 12 января 2020 г.

Непонятное поведение operator string ()

#cpp #классы


Есть некий класс, в очень упрощенном виде выглядит так:

class variant
{
public:
    variant (){};

    template 
    operator T ()
    {
        return T(11);
    }

    operator string ()
    {
        string str = "sss";
        return str;
    }
};


и есть программа:

int main()
{
    variant v1;
    int x1 = v1; // тут все хорошо (вызывается operator int ())
    x1 = v1; // тут тоже все хорошо (вызывается  так же operator int ())

    variant v2;
    string s1 = v2; // тут все хорошо (вызывается operator string ())
    s1 = v2; // тут получаю ошибку компиляции

    return 0;
}


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

error: ambiguous overload for 'operator=' (operand types are 'std::__cxx11::string
{aka std::__cxx11::basic_string}' and 'variant')


что я делаю не так? как правильно перегрузить чтото вроде string operator= (variant)?

компилятор: gcc version 5.1.0 (MinGW-W64 project)
    


Ответы

Ответ 1



Всё просто, в строке string s1 = v2; вызывается конструктор копирования std::string, у которого есть только один вариант аргумента: const std::string&. Поэтому происходит преобразование и всё работает. С другой стороны, строка s1 = v2; вызывает std::string::operator= и тут уже вариантов аргументов куда больше, поэтому компилятор не может определить, в какой тип нужно конвертировать v2. Вылечить это можно только явным преобразованием. На деле получается, что и с явным преобразованием получается та же ошибка. Дальше будут мои спекуляции почему так происходит, чтобы дать ответ точно — нужно штудировать стандарт. Итак, строчка s1 = static_cast(v2); генерирует ту же самую ошибку, тогда как, как заметил Harry, такая строчка: s1 = static_cast(v2); работает как надо. Моё объяснение таково: в первом случае, конвертировать что-то в std::string можно из любого типа, одноаргументный конструктор которого имеет std::string, поэтому, эта строчка генерирует сразу пачку операторов преобразования и мы опять имеем неоднозначность. С другой стороны, когда мы пытаемся преобразовать к ссылке на std::string, получается, что прямое преобразование побеждает — в непрямом нужно сначала создать std::string и только потом можно будет преобразовать к ссылке, т.е. 2 преобразования, а в первом случае нужно только одно. Что нам всё это даёт? Даёт нам это понимание, что если написать код, который запретит шаблонному оператору преобразования участвовать в операциях, когда происходит конвертация в std::string, тогда наш код с преобразованием должен заработать: template using EnableIfNotStr_t = std::enable_if_t::value>; class variant { public: variant() {}; template > operator T () { return T(11); } operator std::string () const { std::string str = "sss"; return str; } }; //... s1 = static_cast(v2);

Комментариев нет:

Отправить комментарий