Re[2]: Function overloading
От: Bell Россия  
Дата: 20.12.05 07:27
Оценка: 13 (2)
Здравствуйте, Greg Zubankov, Вы писали:

GZ>Разбирался в стандарте. Во втором случай operator D* () является наиболее подходящей функцией из-за того что:

GZ>1) она не константная и вызывается у неконстантного объекта 13.3.3.2/3
GZ>и
GZ>2) она возвращает указатель на наиболее базовый класс 13.3.3.2/4

GZ>Именно из-за совокупности этих спецификация она и оказывается наиболее подходящей.


Вот здесь
Автор: Lorenzo_LAMAS
Дата: 21.08.03
все описано очень подробно.
Любите книгу — источник знаний (с) М.Горький
Re[8]: Function overloading
От: Bell Россия  
Дата: 21.12.05 15:28
Оценка: 1 (1) +1
Здравствуйте, Lorenzo_LAMAS, Вы писали:

>>поскольку у нас используются 2 различных conversion functions, то различить последовательности невозможно...

>>А вот в оригинальном примере у нас было 2 user-defined последовательности с одной conversion function...

L_L>Ну а если есть fun(A*) и Test->const Test &->A * и Test->B * -> A* то тут-то различить можно?

Нет — в этих цепочках 2 различные функции преобразования — Test::operator A* и Test::operator B*


>>Сначала для каждой из этих функций определяется лучшая цепочка преобразований (если их несколько), при этом в нашем >случае рассматривается только первая цепочка стандартных преобразований. Из-за этого во втором случае цепочка Test -> const Test -> B* -> A* отбрасывается.


L_L>Из-за чего "из-за этого" ? Поясни причинно следственность

Так. Мы имеем дело с user-defined conversion sequence, а она
... consists of an initial standard conversion sequence followed by a
user-defined conversion (12.3) followed by a second standard conversion sequence.


Есть функция f(A*);. Есть вызов f(t). Есть 2 варианта преобразования Test -> A*:
1. Test -> A*.
2. Test -> const Test -> B* -> A*.
Соответствующие первые цепочки преобразований (initial standard conversion sequence):
1. Test
2. Test -> const Test
первая лучше, и fun(A*) ассоциируется с цепочкой Test -> A*, и в процессе поиска лучшей функции рассматривается только одна эта цепочка.
Любите книгу — источник знаний (с) М.Горький
Re[2]: Function overloading
От: Bell Россия  
Дата: 19.12.05 13:46
Оценка: +2
Здравствуйте, Greg Zubankov, Вы писали:

GZ>Дело в том, что объект s у тебя неконстантный и предпочтение отдается неконстантным функциям.

Тогда "предпочтение неконстантным функциям" должно было сработать и в первом варианте — ведь там тоже одна функция константная, а вторая — нет
Любите книгу — источник знаний (с) М.Горький
Re: Function overloading
От: Greg Zubankov СССР  
Дата: 19.12.05 16:21
Оценка: 2 (1)
Здравствуйте, acoder, Вы писали:

Разбирался в стандарте. Во втором случай operator D* () является наиболее подходящей функцией из-за того что:
1) она не константная и вызывается у неконстантного объекта 13.3.3.2/3
и
2) она возвращает указатель на наиболее базовый класс 13.3.3.2/4

Именно из-за совокупности этих спецификация она и оказывается наиболее подходящей.
Re[6]: Function overloading
От: Bell Россия  
Дата: 21.12.05 14:54
Оценка: 2 (1)
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>Я чего-то туплю и простейших вещей не догоняю. Читать главу 13 тяжко и лениво . Не пояснишь такого (извини, что требую, по сути, объяснения объясненного):

L_L>
L_L>class A{};
L_L>class B : public A{};

L_L>void fun(A *){}
L_L>void fun(B *){}

L_L>class Test {
L_L>public:
L_L>   operator A*()const{return 0;}
L_L>   operator B*(){return 0;}
L_L>};

L_L>int main()
L_L>{
L_L>   Test t;
L_L>   fun(t);
L_L>}
L_L>


L_L>Тут вроде моего скудоумия хватает чтоб понять. Для fun(A *) есть две цепочки (с одинаковым рангом), одна из них лучше, так как в другой добавляется const(*). Для fun(B *) подходит только одна, и теперь есть

L_L>
L_L>fun(A*) Test->B*->A*
L_L>fun(B*) Test->B*
L_L>


L_L>и вторая лучше, так как она — часть первой.

L_L>Теперь, меняем местами const.
L_L>Для fun(A*) лучше начинает подходить Test->A*
L_L>Для fun(B*) подходит только Test->const Test &->B*

L_L>Здесь неоднозначность. Я вот чего не пойму, если в случае (*) наличие const позволило сделать выбор, то почему здесь нельзя так же?


Ты заставил меня засомневаться
Тем не менее попробую объяснить свое вИдение:
Итак, имеется 2 функции-кандидата fun. Сначала для каждой из этих функций определяется лучшая цепочка преобразований (если их несколько), при этом в нашем случае рассматривается только первая цепочка стандартных преобразований. Из-за этого во втором случае цепочка Test -> const Test -> B* -> A* отбрасывается. В результате для fun(A*) получаем цепочку Test -> A* с использованием Test::operator A*, а для fun(B*) — цепочку Test -> const Test -> B*, но уже с использованием Test::operator B*. Далее смотрим 13.3.3.2/3

...
User-defined conversion sequence U1 is a better conversion sequence than 
another user-defined conversion sequence U2 if they contain the same 
user-defined conversion function or constructor and if the second standard 
conversion sequence of U1 is better than the second standard conversion sequence of U2.
...


поскольку у нас используются 2 различных conversion functions, то различить последовательности невозможно...
А вот в оригинальном примере у нас было 2 user-defined последовательности с одной conversion function...
Любите книгу — источник знаний (с) М.Горький
Re[7]: Function overloading
От: Greg Zubankov СССР  
Дата: 19.12.05 14:38
Оценка: :)
Здравствуйте, srggal, Вы писали:

S>Ок, если Вы разобрались, то ткните носом — почему такое происходит.

Курю стандарт
Function overloading
От: acoder  
Дата: 19.12.05 13:19
Оценка:
Не просветит ли кто-нибудь по вопросу function overloading.

Первый пример:
// test1.cpp
struct S {
    operator short* ();
    operator char*  () const;
};

void f (short*);
void f (char*);

void foo (S& s)
{
    f (s);
}

g++ -c test1.cpp
test1.cpp: In function 'void foo(S&)':
test1.cpp:11: error: call of overloaded 'f(S&)' is ambiguous
test1.cpp:6: note: candidates are: void f(short int*)
test1.cpp:7: note:                 void f(char*)

Как я понимаю, логика следующая: S, с помощью user defined conversion, можно превратить в сhar* и в short*. Оба преобразования эквивалентны, следовательно компилятор не может выбрать лучший вариант и выдает ошибку.

Второй пример:
// test2.cpp
struct B {};
struct D : private B {};

void f (B*);
void f (D*);

struct S {
   operator B* () const { return 0; }
   operator D* ()       { return 0; }
};

void foo(S & s)
{
    f(s);
}

g++ -c test2.cpp

Ошибок нет. Под отладчиком проверил — выбирается f(D*). Отличие от первого примера только в том, что char* и short* можно конвертить друг в друга, а B* и D* нет. Но при чем здесь это?

Спасибо.
Re: Function overloading
От: Greg Zubankov СССР  
Дата: 19.12.05 13:37
Оценка:
Здравствуйте, acoder, Вы писали:

A>Не просветит ли кто-нибудь по вопросу function overloading.


A>Первый пример:

A>Как я понимаю, логика следующая: S, с помощью user defined conversion, можно превратить в сhar* и в short*. Оба преобразования эквивалентны, следовательно компилятор не может выбрать лучший вариант и выдает ошибку.
Все верно

A>Второй пример:

A>
A>// test2.cpp
A>struct B {};
A>struct D : private B {};

A>void f (B*);
A>void f (D*);

A>struct S {
A>   operator B* () const { return 0; }
A>   operator D* ()       { return 0; }
A>};

A>void foo(S & s)
A>{
A>    f(s);
A>}
A>

A>
A>g++ -c test2.cpp
A>

A>Ошибок нет. Под отладчиком проверил — выбирается f(D*). Отличие от первого примера только в том, что char* и short* можно конвертить друг в друга, а B* и D* нет. Но при чем здесь это?
Нет это здесь не причем. Здесь дело в const у оператора приведения типа к B*. Если убрать этот квалификатор, будет точно такай же ambiguous call to overloaded function как и в первом примере.
Дело в том, что объект s у тебя неконстантный и предпочтение отдается неконстантным функциям.

A>Спасибо.
Re[2]: Function overloading
От: acoder  
Дата: 19.12.05 13:54
Оценка:
Здравствуйте, Greg Zubankov, Вы писали:


GZ>Нет это здесь не причем. Здесь дело в const у оператора приведения типа к B*. Если убрать этот квалификатор, будет точно такай же ambiguous call to overloaded function как и в первом примере.

GZ>Дело в том, что объект s у тебя неконстантный и предпочтение отдается неконстантным функциям.
Согласен с предыдущим оратором. Для вызова константного оператора надо применить преобразование S -> const S и в первом и во втором примере.
Re[3]: Function overloading
От: srggal Украина  
Дата: 19.12.05 14:12
Оценка:
Здравствуйте, Bell, Вы писали:

B>Здравствуйте, Greg Zubankov, Вы писали:


GZ>>Дело в том, что объект s у тебя неконстантный и предпочтение отдается неконстантным функциям.

B>Тогда "предпочтение неконстантным функциям" должно было сработать и в первом варианте — ведь там тоже одна функция константная, а вторая — нет

+1

Мот 5копеек:

константность оператора приведения играет роль ТОЛЬКО в следующем, модифицированном коде:
// test1.cpp
struct S {
    operator short* ();
    operator char*  () const;
};

void f (short*);
void f (char*);

void foo (const S& s)
{
    f (s);
}


И все становится ОК
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[4]: Function overloading
От: srggal Украина  
Дата: 19.12.05 14:20
Оценка:
Здравствуйте, srggal, Вы писали:

[]

Добавлю, что если Проинвертировать константность в операторах, то получаем тотже амбигоуз

// test2.cpp
struct B {};
struct D : private B {};

void f (B*);
void f (D*);

struct S {
   operator B* ()  { return 0; }
   operator D* () const      { return 0; }
};

void foo(S & s)
{
    f(s);
}
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[5]: Function overloading
От: Greg Zubankov СССР  
Дата: 19.12.05 14:23
Оценка:
Здравствуйте, srggal, Вы писали:

S>Здравствуйте, srggal, Вы писали:


S>[]


S>Добавлю, что если Проинвертировать константность в операторах, то получаем тотже амбигоуз

Инвертировать или убрать. Я уже писал про это.
Кстати private наследование можно заменить на public. Оно ни на что не влияет.
Re[6]: Function overloading
От: srggal Украина  
Дата: 19.12.05 14:27
Оценка:
Здравствуйте, Greg Zubankov, Вы писали:

GZ>Я уже писал про это.

Да, запамятовал.

GZ>Кстати private наследование можно заменить на public. Оно ни на что не влияет.

+1

Ок, если Вы разобрались, то ткните носом — почему такое происходит.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re: Function overloading
От: stasan  
Дата: 19.12.05 15:36
Оценка:
a> Ошибок нет. Под отладчиком проверил — выбирается f(D*). Отличие от
a> первого примера только в том, что char* и short* можно конвертить друг в
a> друга, а B* и D* нет. Но при чем здесь это?

Все верно. Главное отличие здесь — наследование. Дело в том, что B и D не являются эквивалентными с точки зрения перегрузки. D — better match в данном случае, т.к. наследуется от базового класса, т.е. несет более конкретную семантику чем B. Подумайте: к какому типу предпочтительнее привести объект, к базовому или конкретному?
Если бы здесь небыло наследования, то было бы тоже, что и с первым примером.

--
Stas
Posted via RSDN NNTP Server 1.9
Re[2]: Function overloading
От: Greg Zubankov СССР  
Дата: 19.12.05 15:40
Оценка:
Здравствуйте, stasan, Вы писали:

S>Все верно. Главное отличие здесь — наследование. Дело в том, что B и D не являются эквивалентными с точки зрения перегрузки. D — better match в данном случае, т.к. наследуется от базового класса, т.е. несет более конкретную семантику чем B. Подумайте: к какому типу предпочтительнее привести объект, к базовому или конкретному?

S>Если бы здесь небыло наследования, то было бы тоже, что и с первым примером.

Тогда почему отсутствие const у operator B* () приводит к ambiguous call?
Re[2]: Function overloading
От: acoder  
Дата: 19.12.05 19:33
Оценка:
Здравствуйте, Greg Zubankov, Вы писали:

GZ>Разбирался в стандарте. Во втором случай operator D* () является наиболее подходящей функцией из-за того что:

GZ>1) она не константная и вызывается у неконстантного объекта 13.3.3.2/3
GZ>и
GZ>2) она возвращает указатель на наиболее базовый класс 13.3.3.2/4

GZ>Именно из-за совокупности этих спецификация она и оказывается наиболее подходящей.


Да, похоже, что так. Спасибо.
Re[2]: Function overloading
От: Vain Россия google.ru
Дата: 19.12.05 20:20
Оценка:
Здравствуйте, Greg Zubankov, Вы писали:

GZ>Здравствуйте, acoder, Вы писали:


A>>Первый пример:

A>>Как я понимаю, логика следующая: S, с помощью user defined conversion, можно превратить в сhar* и в short*. Оба преобразования эквивалентны, следовательно компилятор не может выбрать лучший вариант и выдает ошибку.
GZ>Все верно
Это ещё почемуже?

// test1.cpp
struct S {
    operator short* ();
    operator char*  () const;
};

void f (short*);
void f (char*);

void foo (S& s)
{
    f (s);
}


g++ -c test1.cpp
test1.cpp: In function 'void foo(S&)':
test1.cpp:11: error: call of overloaded 'f(S&)' is ambiguous
test1.cpp:6: note: candidates are: void f(short int*)
test1.cpp:7: note:                 void f(char*)

f(char*) никакой не кондидат, т.к. ваш оператор приведения к char* работает токо с константными объектами, а неявные приведения в c++ недопустимы.
short* s = NULL;
char* p = &s; //error C2440: 'initializing' : cannot convert from 'short **__w64  ' to 'char *' (MSVC++.NET2002)
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[3]: Function overloading
От: acoder  
Дата: 20.12.05 07:47
Оценка:
Здравствуйте, Vain, Вы писали:

A>>>Как я понимаю, логика следующая: S, с помощью user defined conversion, можно превратить в сhar* и в short*. Оба преобразования эквивалентны, следовательно компилятор не может выбрать лучший вариант и выдает ошибку.

GZ>>Все верно
V>Это ещё почемуже?
Тут я был не прав. short* в char* неявно не преобразовать.

V>f(char*) никакой не кондидат, т.к. ваш оператор приведения к char* работает токо с константными объектами, а неявные приведения в c++ недопустимы.

Только с константными? Т.е. test1.cpp должен компилироваться без ошибок? А если бы у S был бы только один, причем константнынй, оператор приведения типа, он никогда бы не вызвался для неконстантного объекта?
Re[4]: Function overloading
От: Vain Россия google.ru
Дата: 20.12.05 14:23
Оценка:
Здравствуйте, acoder, Вы писали:

A>Здравствуйте, Vain, Вы писали:


V>>f(char*) никакой не кондидат, т.к. ваш оператор приведения к char* работает токо с константными объектами, а неявные приведения в c++ недопустимы.

A>Только с константными? Т.е. test1.cpp должен компилироваться без ошибок?
Я думаю да, но не исключено что вы ошиблись в другом месте, а ошибка "вылезла" здесь.
У меня были случаи когда код не компилился из-за комментария (MSVC++.NET2002)
A>А если бы у S был бы только один, причем константнынй, оператор приведения типа, он никогда бы не вызвался для неконстантного объекта?
Операторы это теже самые методы, которые наследуются при наследовании (public/protected) и им свойственно, то что свойственно обычным методам, но и есть исключения. К примеру, на operator= недопустимо ставить cоnst квалификатор. Поэтому, могу сказать что над константными объектами допустимо вызывать токо методы и операторы с константными квалификаторами.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[5]: Function overloading
От: Аноним  
Дата: 20.12.05 19:04
Оценка:
Здравствуйте, Vain, Вы писали:

V>>>f(char*) никакой не кондидат, т.к. ваш оператор приведения к char* работает токо с константными объектами, а неявные приведения в c++ недопустимы.

A>>Только с константными? Т.е. test1.cpp должен компилироваться без ошибок?
V>Я думаю да, но не исключено что вы ошиблись в другом месте, а ошибка "вылезла" здесь.
V>У меня были случаи когда код не компилился из-за комментария (MSVC++.NET2002)
test1.cpp выдает ambiguos call error и на VS.2003 и на gcc. Причины этого лучше всего описаны здесь
Автор: Lorenzo_LAMAS
Дата: 21.08.03
.

A>>А если бы у S был бы только один, причем константнынй, оператор приведения типа, он никогда бы не вызвался для неконстантного объекта?

V>Операторы это теже самые методы, которые наследуются при наследовании (public/protected) и им свойственно, то что свойственно обычным методам, но и есть исключения. К примеру, на operator= недопустимо ставить cоnst квалификатор. Поэтому, могу сказать что над константными объектами допустимо вызывать токо методы и операторы с константными квалификаторами.
Тем ни менее 13 глава стандарта утверждает иное. Рассмотрим пример:
struct S
{
    void f();
    void f() const;
};

void foo()
{
    S s1;
    s1.f();
}

Компилятору надо определить, какую из двух функции вызвать для выражения s1.f(); Первая стадия — отбор кандидатов. При отборе кандидатов к функциям членам добавляется фиктивный параметр так, что функции f превращаются в:
void f(S&);
void f(S const&);

После этого (опуская некоторые детали) рассматриваются цепочки преобразований типов действительных аргументов к типам формальных аргументов. Для первой функции преобразований не требуется, т.к. s1 неконстантный объект. Для второй функции требуется преобразование S -> const S. Заметим, преобразование вполне корректное. После этого, компилятор выбирает ту функцию, для которой цепочка преобразований самая "короткая". В результате, выбирается неконстантная функция f().

Теперь уберем неконстантную функцию f() из структуры S. Очевидно будет вызываться константный метод, т.к. преобразование S -> const S корректно, а более простых цепочек нет. Что и реализовано во всех компиляторах.

Чуть не забыл, в данном случае компилятор не делает различий для операторов приведения типа и обычных методов. Все вышеприведенные рассуждения применимы и к ним.
Re[6]: Function overloading
От: Vain Россия google.ru
Дата: 20.12.05 19:27
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Vain, Вы писали:


пардон, действительно всё правильно, я напутал со ссылкой, думал что она на константный объект.. :P
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[3]: Function overloading
От: Lorenzo_LAMAS  
Дата: 21.12.05 09:44
Оценка:
B>Вот здесь
Автор: Lorenzo_LAMAS
Дата: 21.08.03
все описано очень подробно.


Т.е. ты из этого объяснения, применив его к текущему примеру все понял?
Of course, the code must be complete enough to compile and link.
Re[4]: Function overloading
От: Bell Россия  
Дата: 21.12.05 13:19
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

B>>Вот здесь
Автор: Lorenzo_LAMAS
Дата: 21.08.03
все описано очень подробно.


L_L>Т.е. ты из этого объяснения, применив его к текущему примеру все понял?


Ну да
Кроме того, сделал для себя открытие:
class A
{
};

class B : public A // (*)
{
};

class Test
{
public:
   operator A() const;
   operator B();
};

void fun(A)
{
}

int main ()
{
   Test t;
   fun(t);
   return 0;
}


Вчера я бы сказал, что при вызове fun будет использован Test::operator A, т.е. цепочка преобразований будет такой: Test -> const Test -> A. Согласно же объяснению ПК, цепочка Test -> B -> A лучше. Проверил на VC7.1 и на VC6 — действительно, вызывается Test::operator B
Любите книгу — источник знаний (с) М.Горький
Re[5]: Function overloading
От: Lorenzo_LAMAS  
Дата: 21.12.05 13:32
Оценка:
Я чего-то туплю и простейших вещей не догоняю. Читать главу 13 тяжко и лениво . Не пояснишь такого (извини, что требую, по сути, объяснения объясненного):
class A{};
class B : public A{};

void fun(A *){}
void fun(B *){}

class Test {
public:
   operator A*()const{return 0;}
   operator B*(){return 0;}
};

int main()
{
   Test t;
   fun(t);
}


Тут вроде моего скудоумия хватает чтоб понять. Для fun(A *) есть две цепочки (с одинаковым рангом), одна из них лучше, так как в другой добавляется const(*). Для fun(B *) подходит только одна, и теперь есть
fun(A*) Test->B*->A*
fun(B*) Test->B*


и вторая лучше, так как она — часть первой.
Теперь, меняем местами const.
Для fun(A*) лучше начинает подходить Test->A*
Для fun(B*) подходит только Test->const Test &->B*

Здесь неоднозначность. Я вот чего не пойму, если в случае (*) наличие const позволило сделать выбор, то почему здесь нельзя так же?
Of course, the code must be complete enough to compile and link.
Re[7]: Function overloading
От: Lorenzo_LAMAS  
Дата: 21.12.05 15:05
Оценка:
>поскольку у нас используются 2 различных conversion functions, то различить последовательности невозможно...
>А вот в оригинальном примере у нас было 2 user-defined последовательности с одной conversion function...

Ну а если есть fun(A*) и Test->const Test &->A * и Test->B * -> A* то тут-то различить можно?

>Сначала для каждой из этих функций определяется лучшая цепочка преобразований (если их несколько), при этом в нашем >случае рассматривается только первая цепочка стандартных преобразований. Из-за этого во втором случае цепочка Test ->> const Test -> B* -> A* отбрасывается.


Из-за чего "из-за этого" ? Поясни причинно следственность
Of course, the code must be complete enough to compile and link.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.