On-line: гостей 0. Всего: 0 [подробнее..]
Программисты всех стран, объединяйтесь!

АвторСообщение



ссылка на сообщение  Отправлено: 28.07.12 15:57. Заголовок: Еще раз о поиске имен и объявлении дружественных функций


Согласно стандарту С++ имя друга (функции или класса), объявленного в некотором классе не будет видно до тех пор, пока само объявление дружественной функции или класса не появится в соответствующем пространстве имен. Чтобы было понятно, то приведу простой пример

namespace N1 
{
struct A
{
friend void f();
};

// здесь имя f не видно

void f();

// здесь имя f становится видным
}


Процитирую соответствующий параграф из стандарта С++ 2011. 7.3.1.2 "Namespace member definitions" #3

"...The name of the friend is not found by unqualified lookup (3.4.1) or by qualified lookup (3.4.3)
until a matching declaration is provided in that namespace scope (either before or after the class definition
granting friendship)...."

Эту фразу из стандарта я понимаю именно так, как я выше описал, продемонстрировав на примере.

Однако компилятор MS VC++ 2010 считает очевидно по-другому, так как он находит имя дружественной функции до его объявления. Приведу пример

#include "stdafx.h" 
#include <iostream>

void f() { std::cout << "::f()\n"; }

namespace N1
{
struct A
{
friend void f();
};

void g() { f(); }

void f() { std::cout << "N1::f()\n"; }
}

int _tmain(int argc, _TCHAR* argv[])
{
N1::g();
}


Я рассуждаю так, опираясь на цитату, приведенную из стандарта, что при определении функции g() компилятор должен видеть только функцию f() из глобального пространтсва имен, так как объявление дружественной функции f() в пространстве имен N1 еще не видно.
Однако вопреки моим ожиданиям при выполнении программы на консоль выводится текст

N1::f()

вместо, как я полагал,

::f()

Поэтому возникает естественный вопрос, то ли я неправильно понимаю данное место в стандарте, то ли компилятор MS VC++ 2010 содержит баг.

Было бы любопытно узнать, как другие компиляторы ведут себя в подобной ситуации, и какой получается результат работы примера.

Я также сообщил о своем мнении, что это баг, по обратной связи с Microsoft. Поэтому с нетерпением жду, что они напишут в ответ.

А пока ответ от Microsoft не пришел, то можно обсудить, у кого какие соображения или контраргументы есть по этому вопросу.

Спасибо: 0 
ПрофильЦитата Ответить
Ответов - 8 [только новые]





ссылка на сообщение  Отправлено: 28.07.12 15:59. Заголовок: Сыроежка пишет: in..


Сыроежка пишет:

 цитата:
in that namespace scope (either before or after the class definition
granting friendship)


Сишник я, мягко говоря, слабый... Но, следуя тексту, что-то про "до или после"... Я понимаю это так, что в пространстве имен N1 имя f() объявлено, а значит видно во всем пространстве.

Спасибо: 0 
Цитата Ответить



ссылка на сообщение  Отправлено: 28.07.12 16:00. Заголовок: PSP пишет: Я понима..


PSP пишет:

 цитата:
Я понимаю это так, что в пространстве имен N1 имя f() объявлено, а значит видно во всем пространстве.



В этом и состоит главная проблема С++, то есть в правильном понимании и интерпретации того, что написано в стандарте. И даже сами разработчики стандарта часто путаются.

Я сначала приведу весь параграф стандарта, чтобы можно было получить более полное представление о вопросе.


 цитата:
3 Every name first declared in a namespace is a member of that namespace. If a friend declaration in a nonlocal
class first declares a class or function95 the friend class or function is a member of the innermost enclosing
namespace. The name of the friend is not found by unqualified lookup (3.4.1) or by qualified lookup (3.4.3)
until a matching declaration is provided in that namespace scope (either before or after the class definition
granting friendship). If a friend function is called, its name may be found by the name lookup that considers
functions from namespaces and classes associated with the types of the function arguments (3.4.2). If the
name in a friend declaration is neither qualified nor a template-id and the declaration is a function or
an elaborated-type-specifier, the lookup to determine whether the entity has been previously declared shall
not consider any scopes outside the innermost enclosing namespace. [ Note: The other forms of friend
95) this implies that the name of the class or function is unqualified.
§ 7.3.1.2 161

declarations cannot declare a new member of the innermost enclosing namespace and thus follow the usual
lookup rules. —end note ] [ Example:
// Assume f and g have not yet been defined.
void h(int);
template <class T> void f2(T);
namespace A {
class X {
friend void f(X); // A::f(X) is a friend
class Y {
friend void g(); // A::g is a friend
friend void h(int); // A::h is a friend
// ::h not considered
friend void f2<>(int); // ::f2<>(int) is a friend
};
};
// A::f, A::g and A::h are not visible here
X x;
void g() { f(x); } // definition of A::g
void f(X) { /* ... */} // definition of A::f
void h(int) { /* ... */ } // definition of A::h
// A::f, A::g and A::h are visible here and known to be friends
}
using A::x;
void h() {
A::f(x);
A::X::f(x); // error: f is not a member of A::X
A::X::Y::g(); // error: g is not a member of A::X::Y
}
—end example ]



Я руководствовался этим примером, который приведен в стандарте. То есть в комментариях к примеру написано, ннапример, // A::f, A::g and A::h are not visible here, поэтому я воспринял это буквально. Но вы посеяли зерна сомнения, выделив место из стандарта про "до и после".

Поэтому было бы очень любопытно узнать, как ведут себя другие компиляторы!



Спасибо: 0 
ПрофильЦитата Ответить



ссылка на сообщение  Отправлено: 28.07.12 16:02. Заголовок: Теперь начинается са..


Теперь начинается самое интересное.Microsoft не хочет признавать ошибку компилятора. Я получил следующий ответ:


 цитата:
Posted by Microsoft on 1/5/2012 at 2:28 PM

Hi: the compiler is behaving correctly in this case. In section 7.3.1.2/p3 of the C++ Standard it states:

"If a friend declaration in a non-local class first declares a class or function the friend class or function is a member of the innermost enclosing namespace."

Jonathan Caves
Visual C++ Compiler Team



В котором просто ссылаются на стандарт, что дружественная функция является членом текущего пространства имен. Такое впечатление, что меня не поняли, то есть либо я чего-то не понимаю, то ли они не понимают Поэтому продолжаем бодаться с Microsoft. Я им отправил комментарий на их ответ


 цитата:
Posted by Сыроежка on 1/6/2012 at 3:45 AM

But further in the same paragraph the following is written "The name of the friend is not found by unqualified lookup (3.4.1) or by qualified lookup (3.4.3) until a matching declaration is provided in that namespace scope (either before or after the class definition granting friendship)." And below this text there is an example in which there is statement
// A::f, A::g and A::h are not visible here.

However due to the example I presented in my feedback the compiler finds the name of the friend before the declaration of the friend in the scope.



Интересно, что они напишут в следующий раз.

Не хотелось бы оставлять этот вопрос невыясненным для себя, иначе непонимание так и останется.

Спасибо: 0 
ПрофильЦитата Ответить



ссылка на сообщение  Отправлено: 28.07.12 16:03. Заголовок: Сыроежка пишет: Инт..


Сыроежка пишет:

 цитата:
Интересно, что они напишут в следующий раз.


Напиши им на русском. Уверен там есть наши !

Спасибо: 0 
Цитата Ответить



ссылка на сообщение  Отправлено: 28.07.12 16:04. Заголовок: Dima пишет: Напиши ..


Dima пишет:

 цитата:
Напиши им на русском. Уверен там есть наши !



Проблема в том, что это общий сайт для всех сообщений о возможных ошибках, которые они принимают к рассмотрению. То есть читать эти сообщения могут все. А английский - это язык межинтернационального общения программистов.

Но если они так и не поймут, чего я добиваюсь, то придется им сказать пару слов по русски!

Спасибо: 0 
ПрофильЦитата Ответить



ссылка на сообщение  Отправлено: 28.07.12 16:05. Заголовок: Получил я ответ на с..


Получил я ответ на свое второе сообщение по этому вопросу, но быстрота ответа вызвало у меня сомнения, что поднятый мною воопрос рассматривался достаточно серьезно.
Но сначала ответ от Microosoft.


 цитата:
Posted by Microsoft on 06.01.2012 at 8:20

Ah yes ... now I see what is going: this is indeed a bug in Visual C++. Unfortunately it is unlikely that we'll be able to fix this for the upcoming release - but we will keep the bug in our database and look at it during the development of a a future release.

Sorry for the confusion and thanks for correcting me.
Jonathan Caves
Visual C++ Compiler Team



А сомнения у меня возникли потому, что после первого отказа признать, что это баг VC++ 2010, я стал задумываться над этим вопросом и что-то смутно припоминать, что в главе 3 стандарта С++, посвященной поиску имен, что-то говорилось о невидимых именах и дружественных функциях.

Поэтому надо будет внимательно почитать главу 3 стандарта. Может быть действительно Microsoft в первом ответе был прав, а второй ответ от них оказался несколько поспешным?

Спасибо: 0 
ПрофильЦитата Ответить



ссылка на сообщение  Отправлено: 28.07.12 16:05. Заголовок: Я нашел еще одно мес..


Я нашел еще одно место в стандарте С++, которое подтвержает мое утверждение о баге компилятора. В разделе 3.4.1 "Unqualified name lookup" в параграфе 3 приводится следующий пример:

typedef int f; 
namespace N {
struct A {
friend void f(A &);
operator int();
void g(A a) {
int i = f(a); // f is the typedef, not the friend
// function: equivalent to int(a)
}
};
}


То есть согласно стандарту в функции g будет вызвана не дружественная функция f, а оператор преобразования типа, так как имя f будет синонимом типа int.
Однако данный код не компилируется MS VC++ 2010, а выдается соообщение об ошибке "error C2440: инициализация: невозможно преобразовать "void" в "int" Выражение, имеющее тип void, нельзя преобразовать в другой тип"

То есть компилятор считает, что в этом месте вызывается дружественнная функция.

Спасибо: 0 
ПрофильЦитата Ответить



ссылка на сообщение  Отправлено: 28.07.12 16:06. Заголовок: Чтобы наглядно увиде..


Чтобы наглядно увидеть, насколько разные компиляторы соответсвуют стандарту, а, следовательно, насколько важно знать программисту стандарт С/С++, чтобы быть уверенным, что имеет место в конкретной ситуации - то ли ваш код некорректный, то ли компилятор не соответсвует стандарту - можно в режиме он-лайн попробвывать выполнить соответсвующий пример кода.

#include	<iostream> 

void f() { std::cout << "::f()\n"; }

namespace N1
{

struct A
{
friend void f();
};

void g() { f(); }

void f() { std::cout << "N1::f()\n"; }

}

int main()
{
N1::g();
}



Как уже было сказано MS VC++ 2010, а также старый компилятор Borland C++ Builder 5.0 (у кого есть компилятор Borland для запуска из командной строки, моогут также проверить работу компилятора с этим кодом) выводят на консоль текст N1::f().
Но если вы этот пример запустите для он-лайн компилятора по ссылке по ссылке , то вы получите уже другой результат, соответствующий стандарту, а именно ::f()
Можете это проделать, скопирово текст примера в окно редактора этого он-лайнового компилятора.


Спасибо: 0 
ПрофильЦитата Ответить
Ответ:
1 2 3 4 5 6 7 8 9
большой шрифт малый шрифт надстрочный подстрочный заголовок большой заголовок видео с youtube.com картинка из интернета картинка с компьютера ссылка файл с компьютера русская клавиатура транслитератор  цитата  кавычки моноширинный шрифт моноширинный шрифт горизонтальная линия отступ точка LI бегущая строка оффтопик свернутый текст

показывать это сообщение только модераторам
не делать ссылки активными
Имя, пароль:      зарегистрироваться    
Тему читают:
- участник сейчас на форуме
- участник вне форума
Все даты в формате GMT  3 час. Хитов сегодня: 37
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет