Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>Есть выражение а + 2; Если а — указатель, ссылка на указатель, массив, ссылка на массив — все ок. Если а
L_L>
L_L>class A
L_L>{
L_L>public:
L_L> operator int *();
L_L>};
L_L>void g()
L_L>{
L_L> A a;
L_L> a + 2;
L_L>}
L_L>
L_L>То тоже все нормально. Но почему в таком случае возникают проблемы? L_L>
L_L>class A
L_L>{
L_L>public:
L_L> typedef int (&RARR_t)[2];
L_L> operator RARR_t();
L_L>};
L_L>void g()
L_L>{
L_L> A a;
L_L> a + 2;
L_L>}
L_L>
L_L>Комо онлайн такое не компилирует. VC 7.1 — все ок.
Имхо, потому что во втором случае требуется 2 преобразования — сначала в ссылку на массив, а потом массив в указатель (то самое преобразование, о котором очень не любит уважаемый Лаптев ), которому уже будет применяться +.
Во всех остальных случаях у тебя сразу участвует либо указатель (как в первом варианте класса А), либо то, что за один шаг к нему приводится (то, что ты написал в первой строчке)
J>Имхо, потому что во втором случае требуется 2 преобразования — сначала в ссылку на массив, а потом массив в указатель (то самое преобразование, о котором очень не любит уважаемый Лаптев ), которому уже будет применяться +. J>Во всех остальных случаях у тебя сразу участвует либо указатель (как в первом варианте класса А), либо то, что за один шаг к нему приводится (то, что ты написал в первой строчке)
Не стану говорить всякие банальности типа г++ (3.2.3) компилит и т.д.
Можно, как мне кажется, придумать похожий пример, где будет встроенный оператор, будет применяться сначала пользовательское преобразование, а потом стандартное и ведь будет же работать?
class A
{
public:
operator int();
}a;
void g()
{
a + 2.;
}
Вот такое можно ведь считать аналогичным?
Of course, the code must be complete enough to compile and link.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>Не стану говорить всякие банальности типа г++ (3.2.3) компилит и т.д. L_L>Можно, как мне кажется, придумать похожий пример, где будет встроенный оператор, будет применяться сначала пользовательское преобразование, а потом стандартное и ведь будет же работать? L_L>
L_L>class A
L_L>{
L_L>public:
L_L> operator int();
L_L>}a;
L_L>void g()
L_L>{
L_L> a + 2.;
L_L>}
L_L>
L_L>Вот такое можно ведь считать аналогичным?
Имхо, нельзя: у встроенного оператора + есть сигнатуры (int,int), (int,double), (double,int), (double,double).
Вот если бы ты написал
g()
{
A a;
std::string s;
s + a; // string::operator+(char)
}
Здравствуйте, Lorenzo_LAMAS, Вы писали:
J>>Имхо, потому что во втором случае требуется 2 преобразования — сначала в ссылку на массив, а потом массив в указатель (то самое преобразование, о котором очень не любит уважаемый Лаптев ), которому уже будет применяться +. J>>Во всех остальных случаях у тебя сразу участвует либо указатель (как в первом варианте класса А), либо то, что за один шаг к нему приводится (то, что ты написал в первой строчке)
L_L>Не стану говорить всякие банальности типа г++ (3.2.3) компилит и т.д. L_L>Можно, как мне кажется, придумать похожий пример, где будет встроенный оператор, будет применяться сначала пользовательское преобразование, а потом стандартное и ведь будет же работать?
L_L>
L_L>class A
L_L>{
L_L>public:
L_L> operator int();
L_L>}a;
L_L>void g()
L_L>{
L_L> a + 2.;
L_L>}
L_L>
L_L>Вот такое можно ведь считать аналогичным?
Плохой пример — здесь, помимо обычных правил разрешения перегружки, работает другое правило: после твоего преобразования к int компилятор имеет бинарный оператор, у которого оба типа — арифметические, и он исполняет для них соответствующее правило 5/9.
В первом же твоем примере у тебя не получалось арифметических типов, так что это правило не срабатывало и работали только обычные правила разрешения перегрузки.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
J>>в сымсле, ты не согласен с моей аргументацией?
L_L>Я просто пока не догнал :))
Ну смотри
Вот компилятор видит твое a+i.
первым делом он, естественно, пытается найти оператор+, принимающий А и int. Не находит.
Тогда он пытается сторговаться на встроенных операторах, используя для этого не более чем одно неявное преобразование каждого операнда.
У нас встроенных операторов всего 2 типа:
1. оба операнда — арифметические
2. один операнд — целый, второй — указатель.
в случае, когда А:
* указатель — все понятно, сразу попадаем в пункт 2.
* ссылка на указатель — неявное преобразование к rvalue, пункт 2
* массив, ссылка на массив — неявное преобразование к указателю, пункт 2
* класс с operator int*() — неявное пользовательское преобразование, пункт 2.
* класс с operator RARR_t() — неявное пользовательское преобразование, не хватает еще одного преобразования к указателю — не компилируем
* класс с operator int(), а i имеет тип float — неявное пользовательское преобразование, попадаем в пункт 1.
В последнем случае, раз уж мы попали на встроенный бинарный оператор для арифметических типов, и типы эти — int и float, мы пользуемся правилом 5/9 для определения типа всего выражения (float) и приведения аргумента int к float.
То, что мы когда-то неявно накатили на a пользовательское преобразование к int, здесь уже никакой роли не играет.
J>>P.S. А что за ошибку комо пишет-то?
L_L>Не нашел оператор + c параметрами типа А, int. L_L>Аналогично ругаются icc, icl, bccx, ti :)
ну у них же вроде edg-шный front-end :)