Максимальное количество определяемых пользователем операторов преобразования может быть неявно применено во время неявного преобразования типа?

Согласно рабочему проекту N3337 (наиболее похожему на опубликованный стандарт ISOC++11) ответ не более одного.

N3337:

К одному значению неявно применяется не более одного определяемого пользователем преобразования (конструктор или функция преобразования).

[ Example:

struct X {
    operator int();
};

struct Y {
    operator X();
};

Y a;
int b = a; // error
           // a.operator X().operator int() not tried

int c = X(a); // OK: a.operator X().operator int()

—end example ]

Но судя по результату компиляции main.cpp с помощью gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4 и запуска a.out с цитируемыми утверждениями в Ubuntu 14.04.3 LTS ответ не более одного.

main.cpp:

#include <iostream>
    
struct As
{
    operator int(){ std::cout<<"operator As::int()"<<std::endl; return 1; }
};

struct Bs
{
    operator int(){ std::cout<<"operator Bs::int()"<<std::endl; return As(); }
};
    
int main()
{
     int i=Bs();
    
     return 0;
}

компиляция и запуск из терминала:

$ g++ -std=c++11 main.cpp
$ ./a.out

результат (вывод):

operator Bs::int()
operator As::int()

Я что-то неправильно понял, или N3337 неправильный, или gcc содержит ошибку?


person Dániel Sándor    schedule 13.02.2016    source источник


Ответы (2)


Здесь не выполняются двойные преобразования.

У вас есть две отдельные конверсии, происходящие в двух разных местах.

Одно преобразование в B::operator int().

Второе преобразование находится в вашем main().

Попробуем обдумать это логически:

Полностью удалите main() из вашей единицы перевода. Видите ли вы какие-либо двойные преобразования?

No.

Теперь давайте создадим заголовочный файл, содержащий следующие биты, назовем его structures.H:

struct As
{
    operator int();
};

struct Bs
{
    operator int();
};

Теперь создайте файл structures.C, содержащий содержимое каждого из этих операторов:

#include <structures.H>

B::operator int(){ std::cout<<"operator As::int()"<<std::endl; return 1; }
A::operator int(){ std::cout<<"operator Bs::int()"<<std::endl; return As(); }

Хорошо, вы все еще видите здесь двойные преобразования? Нет.

Теперь создайте ваш main.C:

#include <structures.H>

int main()
{
     int i=Bs();

     return 0;
}

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

person Sam Varshavchik    schedule 13.02.2016
comment
Я понимаю. В выражении int i=Bs() неявно вызывается только один определяемый пользователем оператор преобразования. (int i=Bs().operator int()) Но другой определяемый пользователем оператор преобразования неявно вызывается в выражении return As(). (return As().operator int()) Таким образом, неявно применяются два определяемых пользователем оператора преобразования. Не в том же выражении, но в цитируемом предложении ничего не говорится об одиночном выражении. Он читает только об одном значении. Мы могли бы сказать, что значения разных вызовов были разными значениями, но тогда оператор int b = a; также будет действительным. - person Dániel Sándor; 13.02.2016
comment
@DánielSándor - просмотрите тот факт, что я привел явный пример, фактический код которого логически И структурно идентичен вашему, за исключением того, что используются две отдельные единицы перевода. Когда компилятор компилирует единицу трансляции main.cpp, он не знает, что находится в другой единице. Нет никакого смысла в том, чтобы один и тот же идентичный код был действительным или нет, в зависимости от того, виден ли другой фрагмент кода в той же единице перевода. Таким образом, хотя это прямо не указано, как таковое, довольно ясно, что это так. - person Sam Varshavchik; 13.02.2016
comment
Извините, должно быть return As(); вместо return 0; ??? Иначе я не понимаю, как A::operator int() называется? - person 眠りネロク; 29.11.2019

int i=Bs(); неявно вызывает Bs::operator int().

return As() неявно вызывает As::operator int().

Это два отдельных выражения.

person Michael Burr    schedule 13.02.2016