Здравствуйте, Alexander G, Вы писали:
AG>Почему перегрузкой метода foo называется случай, когда таких методов более двух, а перегрузкой оператора + для класса называется даже единственное объявление этого оператора?
Перегрузка — это когда имя одно, а аргументы бывают разных типов.
В этом смысле уже "объявлены" перегрузки оператора плюс с типами
int operator+(int,int);
double operator+(double,double);
...
и ты своим объявлением просто добавляешь еще одну перегрузку этого оператора для твоего типа:
Здравствуйте, Alexander G, Вы писали:
AG>Непонятная терминология сбивает с толку.
Дык это, "запомните это дэти, патамушта понять это НЭВОЗМОЖНО!"
IMHO, в С++ и в его терминологии есть много РЕАЛЬНЫХ проблем.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, igna, Вы писали:
I>Ну по той же логике можно было назвать эти две функции перегруженными по this. В конце концов, если функция не виртуальная, различие с функцией не являющейся членом чисто синтаксическое.
Там слишком глубокое синтаксическое различие: x.f ищется исключительно в области видимости класса, тогда как f(x) — во всех подходящих пространствах имён, вплоть до ::
Тогда как оператор сразу ищется во всех подходящих областях, вплоть до ::, где его поджидает встроенный оператор (который, кстати, может и подойти — если у класса есть оператор приведения к примитивному типу).
Здравствуйте, Alexander G, Вы писали:
AG>Почему перегрузкой метода foo называется случай, когда таких методов более двух, а перегрузкой оператора + для класса называется даже единственное объявление этого оператора?
Здравствуйте, Bell, Вы писали:
B>Видимо, из-за наличия встроенного operator +
Перегружена ли функция f в следующем примере?:
struct X {
void f();
};
struct Y {
void f();
};
Вопрос риторический и ответ разумеется ясен, но нет никакого глубокого смысла в том, что определение operator+ называется перегрузкой, а вышеприведенная ситуация нет.
I>А все-таки, перегружают ли друг друга операторы определенные в разных классах?
ну так ты можешь посмотреть, как в стандарте это описано — есть у тебя выражение и какие функции составят множество кандидатов?
Of course, the code must be complete enough to compile and link.
Здравствуйте, Alexander G, Вы писали:
AG>Почему перегрузкой метода foo называется случай, когда таких методов более двух, а перегрузкой оператора + для класса называется даже единственное объявление этого оператора?
IMHO, для успешной разработки и поддержки ПО на С++ это не имеет никакого значения...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Кодт:
К>Иначе можно было бы делать вот такие чудеса К>
struct X {};
struct Y { Y(X); void f(); };
void g(Y);
X x;
g(x); // законное поведение: g(Y(x)), т.к. есть неявное приведение X к Y
x.f(); // внезапно, Y(x).f(), по той же самой причине
Такое преобразование дважды запрещено в 13.3.1/5:
During overload resolution, the implied object argument is indistinguishable from other arguments. The implicit object parameter, however, retains its identity since conversions on the corresponding argument shall obey these additional rules: — no temporary object can be introduced to hold the argument for the implicit object parameter;
— no user-defined conversions can be applied to achieve a type match with it; [...]
igna:
I>А 13.3.1 Candidate functions and argument lists просто случайно находится в 13.3 Overload resolution?
Видимо, "overload resolution" — это историческое название. В современном C++ оно не отражает сути того, что им обозначается в общем случае. "Разрешение перегрузки" может применяться к функциям, которые в действительности не перегружены, но при этом входят в одно множество кандидатов в некотором контексте (например, вследствие применения ADL). Однако раньше такое название могло быть вполне адекватным, т.к. возможность перегрузки функций появилась до того, как в C++ были введены пространства имён, и, вероятно, до введения перегрузки операторов тоже. Почему "overload resolution" не переименовали во что-нибудь вроде "candidate selection" — ХЗ
Здравствуйте, igna, Вы писали:
I>Здравствуйте, Николай Ивченков, Вы писали:
НИ>>Почему "overload resolution" не переименовали во что-нибудь вроде "candidate selection" — ХЗ
I>А может все же проще признать наличие перегрузки здесь?:
I>
Alexander G:
AG>Почему перегрузкой метода foo называется случай, когда таких методов более двух, а перегрузкой оператора + для класса называется даже единственное объявление этого оператора?
Перегрузка оператора и перегрузка функции — разные вещи. Объявляя операторную функцию operator+, ты вводишь новую возможную интерпретацию для выражения вида
+ cast-expression или
additive-expression + multiplicative-expression.
А перегрузка функции имеет место в том случае, если две функции с одинаковым именем объявлены в одном scope:
"When two or more different declarations are specified for a single name in the same scope, that name is said to be overloaded." (см. 13/1)
Здравствуйте, igna, Вы писали:
I>Пусть так. Тем не менее, по какой такой логике имеем перегрузку здесь: I>
I>class A {
I> struct X {};
I> void f(X);
I> struct Y {};
I> void f(Y);
I>};
I>
Здесь у выражения a.f(xy) область поиска f — члены класса A, что определяется из типа выражения a. И мы встречаем две одноимённые функции.
I>Но не здесь?: I>
I>class A {
I> struct X {
I> void f();
I> };
I> struct Y {
I> void f();
I> };
I>};
I>
А здесь у выражения xy.f() область поиска f — либо члены класса X, либо члены класса Y. Но не одновременно.
Логика такая, что при замыкании объект.член компилятор всегда сперва выводит тип объекта и сужает поле зрения для поиска членов.
Иначе можно было бы делать вот такие чудеса
struct X {};
struct Y { Y(X); void f(); };
void g(Y);
X x;
g(x); // законное поведение: g(Y(x)), т.к. есть неявное приведение X к Y
x.f(); // внезапно, Y(x).f(), по той же самой причине
Ничего не мешает тебе сделать язык с этой логикой, но это будет уже не тот С++, который мы знаем.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, Юрий Жмеренецкий, Вы писали:
I>
ЮЖ>>void f();
ЮЖ>>int f();
ЮЖ>>int main(){}
I>
I>А из контекста-то зачем выпадать? Ты давай пример к которому относится "It does not apply to sets of functions fabricated as a result of name lookup (e.g., because of using-directives)".
Вон ты про что. Тогда твой пример:
namespace N {
void f(int) {}
};
using namespace N;
void f(char const*) {}
Только он не ill-formed не потому что "It does not apply to sets of functions fabricated..." а потому, что функции находятся в разных scope (о чем говорится в нормативном тексте выше). А уже из этого следует, что "It does not apply". Примечание можно вообще не рассматривать — ничего не изменится.
А вообще путаница, имхо из-за этого (13.1):
When two or more different declarations are specified for a single name in the same scope, that name is
said to be overloaded.
...
two declarations in the same scope that declare the same name but with different types are called overloaded declarations
Используя это определение, для выяснения наличия перегрузки достаточно найти все объявления в одном scope (и проверить несколько критериев). При этом непосредственно вызов не является необходимым.
Но:
function selection process is called overload resolution
Вот этот процесс выполняется при вызове функции (в выражении) и зависит от контекста вызова:
Overload resolution is a mechanism for selecting the best function to call given a list of expressions that are to be the arguments of the call and a set of candidate functions that can be called based on the context of the call.
Используя это определение, можно попробовать называть перегруженными функции которые участвуют в overload resolution (как процессе). Например, функция считаются перегруженной если set of candidate functions содержит как мимниму дву функции. Но в этом случае наличие факта перегрузки будет зависить от контекста вызова. Т.е. придется говорить "Эта функция перегружена в этом месте вызова, а в этом — нет" (в примечании к 1.9/18 используется оборот "overloaded in a valid context"). Это может показаться логичным, но в этом случае выяснение факта наличия перегрузки усложняется, да и наверняка всплывут какие-нибудь проблемы...
I>struct X {
I> void f();
I>};
I>struct Y {
I> void f();
I>};
I>
I>Вопрос риторический и ответ разумеется ясен, но нет никакого глубокого смысла в том, что определение operator+ называется перегрузкой, а вышеприведенная ситуация нет.
интересно, мне одному непонятно, при чем тут твой пример?
Of course, the code must be complete enough to compile and link.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>покажи мне, как ты во втором случае можешь вызвать в С++ эту функцию, чтобы был вообще смысл говорить о перегрузке.
Здравствуйте, Николай Ивченков, Вы писали:
НИ>Alexander G:
AG>>Почему перегрузкой метода foo называется случай, когда таких методов более двух, а перегрузкой оператора + для класса называется даже единственное объявление этого оператора?
НИ>Перегрузка оператора и перегрузка функции — разные вещи. Объявляя операторную функцию operator+, ты вводишь новую возможную интерпретацию для выражения вида
Так речь то вся идёт о том, что в некоторых случаях вводится первая и единственная возможная интерпретация...
Здравствуйте, Lorenzo_LAMAS, Вы писали:
НИ>>А перегрузка функции имеет место в том случае, если две функции с одинаковым именем объявлены в одном scope:
НИ>>"When two or more different declarations are specified for a single name in the same scope, that name is said to be overloaded." (см. 13/1)
L_L>При этом понятие "имя" в самом начале главы 3 определяется так L_L>
L_L>4 A name is a use of an identifier (2.11), operator-function-id (13.5), literal-operator-id (13.5.8), conversionfunction-
L_L>id (12.3.2), or template-id (14.3) that denotes an entity or label (6.6.4, 6.1).
НИ>>Перегрузка оператора и перегрузка функции — разные вещи. L_L>Так что не надо заострять внимание на том, что разная.
"Надо, Федя. Надо" (c) Шурик.
Встроенным операторам не соответствуют никакие функции. Есть лишь набор псевдо-функций, описанных в 13.6, которые могут рассматриваться только в целях operator overload resolution и только при определённых условиях. В частности, для выражения 1+2 никаких кандидатов не определяется, здесь + сразу же трактуется как встроенный оператор в соответствии с 13.3.1.2/1.
class A
{
int i;
A& operator + (const A&);
};
A a,b;
a = b + a;
ISO/IEC 24765:2008 (Systems and software engineering — Vocabulary):
overload. To assign an operator, identifier, or literal more than one meaning, depending upon the data types associated with it at any given time during program execution
Ты ввёл новое значение для оператора сложения — вот она и перегрузка. Конкретная интерпретация оператора сложения зависит от типов его операндов.
Здравствуйте, Николай Ивченков, Вы писали:
НИ>ISO/IEC 24765:2008 (Systems and software engineering — Vocabulary): НИ>
overload. To assign an operator, identifier, or literal more than one meaning, depending upon the data types associated with it at any given time during program execution
НИ>Ты ввёл новое значение для оператора сложения — вот она и перегрузка. Конкретная интерпретация оператора сложения зависит от типов его операндов.
А вот это уже озвучил jazzer. С этой формулировкой я согласен
Caracrist:
НИ>>Ты ввёл новое значение для оператора сложения — вот она и перегрузка. Конкретная интерпретация оператора сложения зависит от типов его операндов.
C>А вот это уже озвучил jazzer.
Насколько я понял, он решил свести перегрузку операторов к перегрузке операторных функций. Это неверный подход.
Здравствуйте, igna, Вы писали:
I>Вопрос риторический и ответ разумеется ясен, но нет никакого глубокого смысла в том, что определение operator+ называется перегрузкой, а вышеприведенная ситуация нет.
Наверно дело в области видимости еще, которая является частью сигнатуры ф-ии. Для глобального оператора + мы перегружаем его таким же глобальным вариантом.
Здравствуйте, igna, Вы писали:
I>А терминология вообще имеет значение?
Терминология -- это вопрос соглашения. Сейчас, IMHO, проблем с терминологией в обсуждаемом месте нет. Все всех понимают...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, igna, Вы писали:
V>>Наверно дело в области видимости еще, которая является частью сигнатуры ф-ии. Для глобального оператора + мы перегружаем его таким же глобальным вариантом.
I>А чем дело здесь
Издеваешься над нами?
В первом случае перегружается ф-ия A::f для разных аргументов, во втором как ты себе представляешь перегрузку ф-ии A::X::f ф-ией A::Y::f? У них банально имена разные. Могу лишь согласиться с тем, что иногда, без указания полного имени, можно вогнать в ступор компилятор, т.е. ему будет видна более чем одна ф-ия с неполным своим именем f, и мы получим равноправные варианты вывода... ну дык это со-овсем из другой оперы.
Здравствуйте, vdimas, Вы писали:
V>В первом случае перегружается ф-ия A::f для разных аргументов, во втором как ты себе представляешь перегрузку ф-ии A::X::f ф-ией A::Y::f? У них банально имена разные. Могу лишь согласиться с тем, что иногда, без указания полного имени, можно вогнать в ступор компилятор, т.е. ему будет видна более чем одна ф-ия с неполным своим именем f, и мы получим равноправные варианты вывода... ну дык это со-овсем из другой оперы.
Это из другой оперы в соответствие с определением перегрузки в стандарте. Тем не менее нет никакой несгибаемой логики, по которой первый случай называется пекрегрузкой, а второй — нет. А объяснить или попытаться объяснить можно все или почти все.
Имена у них разные. А тут?:
namespace N {
void f(int) {}
};
using namespace N;
void f(char const*) {}
int main()
{
f(123);
f("abcd");
}
igna:
НИ>>А поконкретнее?
I>А конкретнее, причем так, чтоб в лоб и наповал, в стандарте видимо нет. Ну посмотри например тот же 13.1:
I>
I>13.1 Overloadable declarations [over.load]
I> . . .
I>[Note: this
I>restriction applies to explicit declarations in a scope, and between such declarations and declarations made
I>through a using-declaration (7.3.3). It does not apply to sets of functions fabricated as a result of name
I>lookup (e.g., because of using-directives) or overload resolution (e.g., for operator functions). ]
Посмотрел. Функции в разных scope не являются перегруженными, потому и конфликтов не возникает. Как с информативным, так и с нормативным текстом стандарта это очень даже хорошо согласуется.
Почему перегрузкой метода foo называется случай, когда таких методов более двух, а перегрузкой оператора + для класса называется даже единственное объявление этого оператора?
.
мне кажется, я понял тебя.
вообще, все это не так уж важно, имхо.
мне кажется, что твой пример с нестатической функцией членом (не оператором) — тут о перегрузке говорить и не приходится, т.к.
что ты будешь вызывать ее с ".", что в области видимости класса — там не будет функции из другого класса Y. А вот с операторами — другое дело, т.к. они есть встроенные.
Of course, the code must be complete enough to compile and link.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, Bell, Вы писали:
B>>Видимо, из-за наличия встроенного operator +
I>Перегружена ли функция f в следующем примере?:
I>
I>struct X {
I> void f();
I>};
I>struct Y {
I> void f();
I>};
I>
I>Вопрос риторический и ответ разумеется ясен, но нет никакого глубокого смысла в том, что определение operator+ называется перегрузкой, а вышеприведенная ситуация нет.
Использование операторов, перегруженных для пользовательских типов, обычно происходит без обращения к "class member access syntax", в отличие от функций-членов. Т.е. при взгляде на код кажется, что перегруженный оператор не является членом класса, а есть перегрузка внешней по отношению к классу функции...
Может быть из-за этого ИМХО, конечно.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>что ты будешь вызывать ее с ".", что в области видимости класса — там не будет функции из другого класса Y.
Ну по той же логике можно было назвать эти две функции перегруженными по this. В конце концов, если функция не виртуальная, различие с функцией не являющейся членом чисто синтаксическое. Сравни:
struct X {};
void f(X);
struct Y {};
void f(Y);
struct X {
void f();
};
struct Y {
void f();
};
Почему-то в первом случае имеем перегрузку, во втором — нет.
Здравствуйте, igna, Вы писали:
I>А если оператор используется в форме вызова функции a.operator=(b), поджидает ли его также встроенный оператор?
Нет, не поджидает. Но в стандарт за пунктами лезть, если честно, влом.
Caracrist:
AG>>>Почему перегрузкой метода foo называется случай, когда таких методов более двух, а перегрузкой оператора + для класса называется даже единственное объявление этого оператора?
НИ>>Перегрузка оператора и перегрузка функции — разные вещи. Объявляя операторную функцию operator+, ты вводишь новую возможную интерпретацию для выражения вида
C>Так речь то вся идёт о том, что в некоторых случаях вводится первая и единственная возможная интерпретация...
НИ>А перегрузка функции имеет место в том случае, если две функции с одинаковым именем объявлены в одном scope:
НИ>"When two or more different declarations are specified for a single name in the same scope, that name is said to be overloaded." (см. 13/1)
При этом понятие "имя" в самом начале главы 3 определяется так
4 A name is a use of an identifier (2.11), operator-function-id (13.5), literal-operator-id (13.5.8), conversionfunction-
id (12.3.2), or template-id (14.3) that denotes an entity or label (6.6.4, 6.1).
НИ>Перегрузка оператора и перегрузка функции — разные вещи.
Так что не надо заострять внимание на том, что разная.
Of course, the code must be complete enough to compile and link.
Здравствуйте, Николай Ивченков, Вы писали:
НИ>Caracrist:
AG>>>>Почему перегрузкой метода foo называется случай, когда таких методов более двух, а перегрузкой оператора + для класса называется даже единственное объявление этого оператора?
НИ>>>Перегрузка оператора и перегрузка функции — разные вещи. Объявляя операторную функцию operator+, ты вводишь новую возможную интерпретацию для выражения вида
C>>Так речь то вся идёт о том, что в некоторых случаях вводится первая и единственная возможная интерпретация...
НИ>В каких случаях?
class A
{
int i;
};
A a,b;
a = b + a;
какая тут интерпретация?
--------
class A
{
int i;
A& operator + (const A&);
};
A a,b;
a = b + a;
Здравствуйте, Кодт, Вы писали:
К>Там слишком глубокое синтаксическое различие: x.f ищется исключительно в области видимости класса, тогда как f(x) — во всех подходящих пространствах имён, вплоть до ::
Помещаем все в класс:
class A {
struct X {};
void f(X);
struct Y {};
void f(Y);
};
class A {
struct X {
void f();
};
struct Y {
void f();
};
};
"Глубокое синтаксическое различие" превратилось в "мелкое", тем не менее в первом случае имеем перегрузку, во втором — нет.
Здравствуйте, igna, Вы писали:
I>"Глубокое синтаксическое различие" превратилось в "мелкое", тем не менее в первом случае имеем перегрузку, во втором — нет.
Ничто никуда не превратилось, поскольку "различие" было между свободными функциями и функциями-членами.
А у тебя в обоих случаях — функции-члены.
Здравствуйте, vdimas, Вы писали:
V>Наверно дело в области видимости еще, которая является частью сигнатуры ф-ии. Для глобального оператора + мы перегружаем его таким же глобальным вариантом.
Здравствуйте, Николай Ивченков, Вы писали:
НИ>Такое преобразование дважды запрещено в 13.3.1/5:
Говоря "такое", не забудь указать, какое именно. Там было f(x) и x.f() Из них одно разрешено уже сейчас, а второе К>>Ничего не мешает тебе сделать язык с этой логикой, но это будет уже не тот С++, который мы знаем.
И плевать мы хотели на стандарт, если делаем свой собственный язык.
Кодт:
НИ>>Такое преобразование дважды запрещено в 13.3.1/5:
К>Говоря "такое", не забудь указать, какое именно.
Естественно, то, которое подразумевалось в x.f(). В g(x) никаких "чудес" не наблюдается.
К>>>Из них одно разрешено уже сейчас, а второе К>>>Ничего не мешает тебе сделать язык с этой логикой, но это будет уже не тот С++, который мы знаем. К>И плевать мы хотели на стандарт, если делаем свой собственный язык.
Чтобы "сделать язык с этой логикой" из C++, недостаточно изменить только лишь правила поиска имён.
Здравствуйте, igna, Вы писали:
I> Имена у них разные. А тут?:
И тут разные, в чем проблема-то? Вот еще более частый случай:
void f();
class A {
void f();
void f1();
};
void A::f1() { f(); }
Нет тут никакой перегрузки. В похожих случаях компилятор или определит полное имя ф-ии, или выдаст ошибку, в случае множества равнозначных вариантов. Правила вывода операндов для перегруженных ф-ий действуют только на ф-ии с одинаковым _полным_ именем, ибо только они и есть перегруженные. Т.е., сначала компилятор ищет function group, к которой принадлежит эта ф-ия, и только уже внутри группы — самую подходящую перегрузку.
ИМХО, весь спор от того, что бинарные операторы разрешено определять как мемберы (имею ввиду нестатические мемберы), а это грубый косяк дизайна языка, порождающий подобные нелепые вопросы. Надо просто понимать, что это косяк, и стараться не пользоваться и не грузить себя и других мягко говоря чепухой. Мне понятны мотивы этого косяка: например, если делаем не-глобальную операцию +, которая оперирует закрытыми членами, мы экономим на лишних определениях friend operator+(), ну дык все-равно надо было разрешить лишь статическую форму оператора, как это сделано в C#, расширив соответствующим образом правила поиска _переопределенного_ (не обязательно _перегруженного_ в этом случае) оператора.
Ты думаешь, что твой случай сильно от моего отличается? Или неймспейсы у нас уже не являются составляющим имени? Перегрузки никакой нет. N::f и ::f — это разные function group. Или тебя удивляет, что компилятор способен находить наиболее подходящую ф-ию из всех доступных в области видимости function groups?
igna:
I>Это из другой оперы в соответствие с определением перегрузки в стандарте. Тем не менее нет никакой несгибаемой логики, по которой первый случай называется пекрегрузкой, а второй — нет. А объяснить или попытаться объяснить можно все или почти все.
I> Имена у них разные. А тут?:
I>
То, что функции могут входить в одно множество кандидатов, не означает, что они перегруженные. Но если функции перегруженные, то в какое-либо множество кандидатов они могут входить только все вместе.
Твой пример можно очень просто переделать так, что N::f и ::f будут являться кандидатами порознь:
namespace N {
void f(int) {}
};
using namespace N;
void f(char const*) {}
struct A
{
operator int() const { return 0; }
operator char const *() const { return 0; }
};
int main()
{
N::f(A()); // OK
::f(A()); // OK
f(A()); // ill-formed
}
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, igna, Вы писали:
V>Ты думаешь, что твой случай сильно от моего отличается? Или неймспейсы у нас уже не являются составляющим имени? Перегрузки никакой нет. N::f и ::f — это разные function group. Или тебя удивляет, что компилятор способен находить наиболее подходящую ф-ию из всех доступных в области видимости function groups?
Разве он находит ее не в соответствии с 13.3 Overload resolution стандарта?
Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>Тогда такой вариант не должен компилироваться:
ЮЖ>namespace N {
ЮЖ> void f() {}
ЮЖ>};
ЮЖ>using namespace N;
ЮЖ>int f() { return 0;} // "перегруженная" функция отличается только возращаемым типом
ЮЖ>int main(){ f(); }
Для того, чтобы этот вариант компилировался, в стандарте есть исключение:
13.1 Overloadable declarations [over.load]
1 Not all function declarations can be overloaded. Those that cannot be overloaded are specified here. A
program is ill-formed if it contains two such non-overloadable declarations in the same scope. [Note: this
restriction applies to explicit declarations in a scope, and between such declarations and declarations made
through a using-declaration (7.3.3). It does not apply to sets of functions fabricated as a result of name
lookup (e.g., because of using-directives) or overload resolution (e.g., for operator functions). ]
igna:
I>Для того, чтобы этот вариант компилировался, в стандарте есть исключение:
I>
I>13.1 Overloadable declarations [over.load]
I>1 Not all function declarations can be overloaded. Those that cannot be overloaded are specified here. A
I>program is ill-formed if it contains two such non-overloadable declarations in the same scope. [Note: this
I>restriction applies to explicit declarations in a scope, and between such declarations and declarations made
I>through a using-declaration (7.3.3). It does not apply to sets of functions fabricated as a result of name
I>lookup (e.g., because of using-directives) or overload resolution (e.g., for operator functions). ]
Примечания не являются нормативными (и обязательными для прочтения текста стандарта).
Здравствуйте, Николай Ивченков, Вы писали:
НИ>А поконкретнее?
А конкретнее, причем так, чтоб в лоб и наповал, в стандарте видимо нет. Ну посмотри например тот же 13.1:
13.1 Overloadable declarations [over.load]
. . .
[Note: this
restriction applies to explicit declarations in a scope, and between such declarations and declarations made
through a using-declaration (7.3.3). It does not apply to sets of functions fabricated as a result of name
lookup (e.g., because of using-directives) or overload resolution (e.g., for operator functions). ]
То есть "functions fabricated as a result of name lookup (e.g., because of using-directives)" тоже вносят вклад в перегрузку, только им разрешено например отличаться типом возвращаемого параметра.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>>Тогда такой вариант не должен компилироваться:
I>
ЮЖ>>namespace N {
ЮЖ>> void f() {}
ЮЖ>>};
ЮЖ>>using namespace N;
ЮЖ>>int f() { return 0;} // "перегруженная" функция отличается только возращаемым типом
ЮЖ>>int main(){ f(); }
I>Для того, чтобы этот вариант компилировался, в стандарте есть исключение:
Исключение из чего? Этот пример не подпадает под выделенное:
I>
I>13.1 Overloadable declarations [over.load]
I>1 Not all function declarations can be overloaded. Those that cannot be overloaded are specified here. A
I>program is ill-formed if it contains two such non-overloadable declarations in the same scope.
igna:
ЮЖ>>Исключение из чего? Этот пример не подпадает под выделенное:
I>Правда? А на мой взгляд как раз подпадает.
Так scope-то разные.
"A namespace member name has namespace scope." (3.3.5/1)
Например, имя функции скрывает имя класса, объявленного в том же scope: "If a class or enumeration name and an object, function, or enumerator are declared in the same scope (in any order) with the same name, the class or enumeration name is hidden wherever the object, function, or enumerator name is visible." (3.3.7/2). Для разных scope это не работает:
struct x {};
struct y {};
void x() {}
namespace
{
void y();
}
int main()
{
x(); // well-formed: x is function
y(); // ill-formed: y is ambiguous
}
Здравствуйте, igna, Вы писали:
I>Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>>Исключение из чего? Этот пример не подпадает под выделенное:
I>Правда? А на мой взгляд как раз подпадает. Если нет, не мог бы ты привести пример подпадающий под то самое выделенное?
void f();
int f();
int main(){}
PS: в том моем примере вызов 'f' в 'main' — лишний.
А из контекста-то зачем выпадать? Ты давай пример к которому относится "It does not apply to sets of functions fabricated as a result of name lookup (e.g., because of using-directives)".
Здравствуйте, Николай Ивченков, Вы писали:
НИ>Посмотрел. Функции в разных scope не являются перегруженными, потому и конфликтов не возникает. Как с информативным, так и с нормативным текстом стандарта это очень даже хорошо согласуется.
При таком понимании стандарта осталось только найти пример, к которому можно применить тот самый информативный текст.
Здравствуйте, Юрий Жмеренецкий, Вы писали:
I>>Ты давай пример к которому относится "It does not apply to sets of functions fabricated as a result of name lookup (e.g., because of using-directives)".
ЮЖ>Вон ты про что. Тогда твой пример:
ЮЖ>Только он не ill-formed не потому что "It does not apply to sets of functions fabricated..."
Ну вот я как раз просил примера оправдывающего наличие этого "It does not apply to sets of functions fabricated as a result of name lookup (e.g., because of using-directives)" в стандарте.
ЮЖ>
Overload resolution is a mechanism for selecting the best function to call given a list of expressions that are to be the arguments of the call and a set of candidate functions that can be called based on the context of the call.
ЮЖ>Используя это определение, можно попробовать называть перегруженными функции которые участвуют в overload resolution (как процессе). Например, функция считаются перегруженной если set of candidate functions содержит как мимниму дву функции. Но в этом случае наличие факта перегрузки будет зависить от контекста вызова. Т.е. придется говорить "Эта функция перегружена в этом месте вызова, а в этом — нет" (в примечании к 1.9/18 используется оборот "overloaded in a valid context").
И именно такое понимание стандарта демонстрируют VC++ 9.0 и Comeau.
Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>Здравствуйте, igna, Вы писали:
I>>И именно такое понимание стандарта демонстрируют VC++ 9.0 и Comeau.
ЮЖ>Не только:
int f();
ЮЖ>void f();
ЮЖ>//...
ЮЖ>// C2556: 'void f(void)' : overloaded function differs only by return type from 'int f(void)'
Что "не только", не только VC++ 9.0 и Comeau или что? И кстати, ты вот этот пример видел?:
namespace N {
void f(int) {}
}
using namespace N;
void f(int) {}
int main()
{
f(1); // error C2668: 'f' : ambiguous call to overloaded function
}
Компилятор считает f overloaded, что вроде не совпадает с твоим мнением, так?
Здравствуйте, igna, Вы писали:
V>>Ты думаешь, что твой случай сильно от моего отличается? Или неймспейсы у нас уже не являются составляющим имени? Перегрузки никакой нет. N::f и ::f — это разные function group. Или тебя удивляет, что компилятор способен находить наиболее подходящую ф-ию из всех доступных в области видимости function groups?
I>Разве он находит ее не в соответствии с 13.3 Overload resolution стандарта?
Не только в соответствии с этим пунктом стандарта, ибо используются и другие пункты стандарта тоже.
А вообще, спор ведь терминологический. Попробую более четко сформировать в самом конце, а пока пара размышлизмов.
Сама терминология эта пошла еще с тех времен, когда не было неймспейсов, и была "честная" перегрузка одного и того же имени ф-ии. Но тогда проблемы терминологии не было, ибо эта проблема "перегрузки" в разных скопах нивелировалась сокрытием сигнатур, например как в наследнике переопределенная ф-ия скрывает одноименные ф-ии из базового класса, а не перегружает их, или как это происходит в локальном контексте:
void f(char*);
void g() {
extern void f(int);
f("asd"); // error, there is no f(char*) in this scope
}
А сейчас бардак, мягко говоря. Смотри, разве нестатический метода класса может перегрузить глобальную ф-ию? Ну вот исходя из здравого смысла? А внутри ф-ии члена? Этот процесс тоже описан в указанном тобой пункте стандарта при формировании candidate functions set.
Я тут уже пользовался терминологией из стандарта другого C-подобного языка, ИМХО там введен очень удачный термин function group, который есть семейство одноименных перегруженных ф-ий, а вовсе не аморфный candidate functions set как в стандарте С++. Ведь сейчас ситуация такова, что не можешь сказать, перегружает одна ф-ия другую или нет без контекста (и твои примеры именно это и демонстрируют). Просто получается так, что перегрузка ф-ий друг другом — это не св-во конкретной пары ф-ий, а внешнее, по отношению к ним св-во, определяемое контекстом вызова.
Все твои примеры можно свести было к этому:
// "сами по себе" ф-ии не перегружают друг друга namespace M { void f(int); }
namespace N { void f(char*); }
namespace {
using namespace N;
using namespace M;
// это определяется контекстом
f("asd");
}
Т.е. вывод такой, что однозначно о перегрузке набора ф-ий как неотъемлимом св-ве самого этого набора (что я имел ввиду все предыдущие посты) можно говорить лишь тогда, когда у них одинаковое полное имя (не символьно одинаковое, а семантически, ибо нейспейсы могут быть одноименны с типами) и одинаковая видимость и доступ. Все остальные случаи — суть наведенные эффекты конкретного контекста. Все.
Здравствуйте, vdimas, Вы писали:
V>Я тут уже пользовался терминологией из стандарта другого C-подобного языка, ИМХО там введен очень удачный термин function group, который есть семейство одноименных перегруженных ф-ий, а вовсе не аморфный candidate functions set как в стандарте С++.
Ты C# имеешь ввиду?
V>Ведь сейчас ситуация такова, что не можешь сказать, перегружает одна ф-ия другую или нет без контекста (и твои примеры именно это и демонстрируют).
Здравствуйте, igna, Вы писали:
I>Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>>Здравствуйте, igna, Вы писали:
I>>>И именно такое понимание стандарта демонстрируют VC++ 9.0 и Comeau.
ЮЖ>>Не только: I>
int f();
ЮЖ>>void f();
ЮЖ>>//...
ЮЖ>>// C2556: 'void f(void)' : overloaded function differs only by return type from 'int f(void)'
ЮЖ>>Здесь контекст есть. А вот в отношении деклараций нельзя сказать перегрузка присутствует.
I>Ну так сообщение об ошибке компилятора (или сообщение компилятора об ошибке) верно?
Нет. "По стандарту" должно быть что-то вроде "overload resolution fails", с указанием того, что 'best viable' функция не уникальна (+ показать их список).
Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>Нет. "По стандарту" должно быть что-то вроде "overload resolution fails", с указанием того, что 'best viable' функция не уникальна (+ показать их список).
Нда. Тем не менее GCC 4.1.2 хотя и выдает вожделенный список тоже называет f overloaded. Да и Comeau.