Форум программистов, компьютерный форум CyberForum.ru

C++

Войти
Регистрация
Восстановить пароль
 
 
ASCII
90 / 62 / 10
Регистрация: 15.12.2013
Сообщений: 399
Завершенные тесты: 2
#1

Friend declaration construction - C++

16.07.2016, 04:27. Просмотров 992. Ответов 36
Метки нет (Все метки)

Читаю C++ Templates. The Complete Guide. Вандервурд, Джоссатис
В одной из глав речь идет об объявлениях дружественных конструкций.

Основная идея такова:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
template <typename T1, typename T2>
void combine(T1, T2);
 
class Mixer
{
    friend void combine<>(int, int);
    friend void combine<int, int>(int, int);
    friend void combine<char>(char, int);
 
    // errors
    friend void combine<char>(char&, int);
    friend void combine<>(long, long) {  }
};
Можно объявить дружественной шаблон функции. Если можно вывести аргументы шаблона, угловые скобки могут быть пустыми.
Определение специализации шаблона запрещено.

Но говорится и о втором варианте объявления дружественных конструкций, в котором угловые скобки вообще опускаются.
В качестве пояснения, даются два правила:

1) Если имя не полное (без указания пространств имен или класса), то такое имя может ссылаться только на обычную функцию.
При этом, если в точке объявления функции в качестве дружественной она еще не была объявлена, то дружественная конструкция,
ее первое объявление, в таком случае оно может быть и определением.



2) Если имя полное (содержит :: ), то оно должно ссылаться на ранее объявленную функцию или шаблон функции.
Предпочтение отдается функции перед шаблоном функции. Не может быть определения.


Дается разъясняющий пример:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
void multiply(void*);
 
template <typename T>
void multiply(T);
 
class Pride
{
public:
    friend void multiply(int) { }           /* имя не полное, может быть определением */
    friend void ::multiply(void*);        /* имя полное, ссылается на обычную функцию */
    friend void ::multiply(int);            /* имя полное, ссылается на шаблон функции для типа int */
    friend void ::multiply<double*>(double*); /* также могут быть и угловые скобки */
};
Проблема возникает для:

C++
1
    friend void ::multiply(int);  /* имя полное, ссылается на шаблон функции для типа int */
Если переписать этот пример вот так, для проверки дружественности специализации шаблона функции
multiply<int> классу Mixer:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void multiply(void*);
 
template <typename T>
void multiply(T);
 
class Pride
{
    int p;
public:
    friend void multiply(int) { }
    friend void ::multiply(void*);
    friend void ::multiply(int);
    friend void ::multiply<double*>(double*);
};
 
template <>
void multiply(double*)
{
    Pride pr;
    pr.p = 0; /* тут все нормально */
}
 
template <>
void multiply(int)
{
    Pride pr;
    pr.p = 0; /* а тут ошибка, то есть эта специализация не является дружественной */
}
Почему так?
Миниатюры
Friend declaration construction  
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
16.07.2016, 04:27     Friend declaration construction
Посмотрите здесь:

Ошибка: friend declaration declares a non-template function - C++
Всем доброго времени суток! Я корплю над задачкой: нада сделать класс вектор шаблонным, перегрузить операции ввода-вывода, и тд и тп. ...

Перегрузка операторов, friend или нет friend? - C++
Всем здравствуйте. Есть такой вопрос: при перегрузке операторов в классе(пусть будут + и = (вообще неважно, за исключением потока)) как и...

Friend для friend - C++
всем доброго времени суток, покажу проблему на примере: Class B; class A{ int F; friend B; public: A(){F=0;}; };

Класс friend - C++
Проблемка с доступом через дружественный класс: class Game { friend Player; //тут объявлен класс-друг ...

Не работает friend - C++
#ifndef INTEGERLONGS_HPP_INCLUDED #define INTEGERLONGS_HPP_INCLUDED...

friend function - C++
Помогите плз разобраться: Когда я делаю инкремент &quot;х&quot; через закрытые функции класса - все работает нормально, а когда через...

friend function - C++
После добавления дружественной ф-ции sum( а она для сложения salary у человека, которого я выберу) класс перестал работать. Что у меня не...

После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
hoggy
6437 / 2655 / 460
Регистрация: 15.11.2014
Сообщений: 5,847
Завершенные тесты: 1
16.07.2016, 05:44     Friend declaration construction #2
рассмотрим код:
http://rextester.com/ZFGA41569

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
 
 
void multiply(void*);
 
template <typename T>
void multiply(T);
 
class Pride
{
    int p;
public:
    friend void multiply(int) { }
    friend void ::multiply(void*);
    friend void ::multiply(int);
    friend void ::multiply<double*>(double*);
};
 
template <>
void multiply(double*)
{
    Pride pr;
    pr.p = 0; /* тут все нормально */
    (void)pr;
    
}
 
template <>
void multiply(int)
{
    Pride pr;
    pr.p = 0; /* а тут ошибка, то есть эта специализация не является дружественной */
    (void)pr;
}
 
 
int main()
{
    std::cout << "Hello, world!\n";
}
главное на что нужно обратить внимание:
выхлоп компилятора:
Код
Error(s):
source_file.cpp:17:31: warning: ‘void multiply(int)’ is already a friend of class ‘Pride’
     friend void ::multiply(int);
                               ^
source_file.cpp: In function ‘void multiply(T) [with T = int]’:
source_file.cpp:13:9: error: ‘int Pride::p’ is private
     int p;
         ^
source_file.cpp:34:8: error: within this context
     pr.p = 0; /* а тут ошибка, то есть эта специализация не является дружественной */
        ^
что произошло?

в строке:
C++
1
friend void multiply(int) { }
в глобальном пространстве возникло определение функции обычной не шаблонной функции,
которая является другом класса.

далее в строке:
C++
1
friend void ::multiply(int);
указание что эта обычная не шаблонная функция - друг.

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

если написать так:
C++
1
friend void ::multiply<int>(int);
то компилятору явно указывается,
что друг - специализация шаблона под конкретный параметр.
он уже не сможет спутать такой синтаксис с не шаблонной функцией,
и все работает как часы.
ASCII
90 / 62 / 10
Регистрация: 15.12.2013
Сообщений: 399
Завершенные тесты: 2
16.07.2016, 14:19  [ТС]     Friend declaration construction #3
hoggy, я убрал определение обычной функции, но оставил
C++
1
friend void ::multiply(int);
Тем не менее ошибка. То есть можно сделать вывод, что в книге ошибка? В частности второе правило?
hoggy
6437 / 2655 / 460
Регистрация: 15.11.2014
Сообщений: 5,847
Завершенные тесты: 1
16.07.2016, 15:04     Friend declaration construction #4
Цитата Сообщение от ASCII Посмотреть сообщение
То есть можно сделать вывод, что в книге ошибка?
хм...
вопрос интересный.

вот что я нашел в стандарте:
11.3 Friends

6 A function can be defined in a friend declaration of a class if and only if the class is a non-local class (9.8),
the function name is unqualified, and the function has namespace scope.
если я правильно все понял,
то дружественные функции не могут быть квалифицированы.
(иметь полное имя)

они всегда определяются в том же пространстве имен,
что и класс, в котором они объявляются.

то есть, тут уже идет какое то расхождение с книгой...

похоже на то, что компилятор встретив
нешаблоное объявление функции-друга,
и воспринимает его, как не шаблонное.
ASCII
90 / 62 / 10
Регистрация: 15.12.2013
Сообщений: 399
Завершенные тесты: 2
16.07.2016, 15:26  [ТС]     Friend declaration construction #5
Цитата Сообщение от hoggy Посмотреть сообщение
то дружественные функции не могут быть квалифицированы.
(иметь полное имя)
Вообще никакие?
А разве

C++
1
friend void ::multiply(void*);
Не qualified name?
Надо покопаться в стандарте
Nosey
1346 / 397 / 107
Регистрация: 22.10.2014
Сообщений: 861
Завершенные тесты: 2
16.07.2016, 15:35     Friend declaration construction #6
Сообщение было отмечено автором темы, экспертом или модератором как ответ
ASCII, Вместо правил книги, мне кажутся правила стандарта легче воспринимаются:

Цитата Сообщение от 14.5.4 Friends
— if the name of the friend is a qualified or unqualified template-id, the friend declaration refers to a
specialization of a function template, otherwise
— if the name of the friend is a qualified-id and a matching non-template function is found in the specified
class or namespace, the friend declaration refers to that function, otherwise,
— if the name of the friend is a qualified-id and a matching function template is found in the speci-
fied class or namespace, the friend declaration refers to the deduced specialization of that function
template (14.8.2.6), otherwise,
— the name shall be an unqualified-id that declares (or redeclares) an ordinary (non-template) function.
Все кроме 3-его правила , я например его не понимаю, и собственно это правило как раз разрешает ваше объявление
C++
1
friend void ::multiply(int);
На практике "это правило" не привязывает дружественность к специализации шаблона, а может привязать к общей шаблонной функции.
Т.е. ваше верхнее объявление привязывает дружественность к
C++
1
2
template <typename T>
void multiply(T) {// where T = int}
И кладет болт на специализацию.
Можно предположить что объявление специализации перед определением класса - решило бы проблему:
C++
1
2
3
4
5
6
7
8
template <typename T>
void multiply(T);
 
template <>
void multiply<int>(int);
// класс
 
// реализация специализации
но такого не происходит

Все это слишком похоже на баг, но вот проблема что этот баг одинаков на "всех" компиляторах .
Как расшифровывать 3-е правило я не понимаю.

Если мы определим дружественность таким образом:
C++
1
friend void ::multiply<>(int);
То мы попадем в первое правило, которое верно отрабатывает на "всех" компиляторах.

Цитата Сообщение от hoggy Посмотреть сообщение
если я правильно все понял,
то дружественные функции не могут быть квалифицированы.
(иметь полное имя)
Вам не кажется что это бред?
Ну и к тому же в стандарте приведен пример рассказывающий что относится к "инлайн" определению функции, аля :
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
 
class Pride
{
    friend void f() {std::cout << "Да, я в глобальном пространстве, и не смотрите где я написана" << std::endl;}
};
 
void f();
 
int main()
{
    f();
}
avgoor
884 / 519 / 112
Регистрация: 05.12.2015
Сообщений: 1,464
16.07.2016, 15:54     Friend declaration construction #7
Цитата Сообщение от hoggy Посмотреть сообщение
если я правильно все понял,
то дружественные функции не могут быть квалифицированы.
Вы не правильно поняли.
Вот так можно:
C++
1
2
3
4
5
6
7
8
9
10
11
class A
{
    int a;
    friend void foo(A& a) { a.a = 1; }
};
 
int main()
{
    A a;
    foo(a);
}
А если foo квалифицировать - то нельзя.
hoggy
6437 / 2655 / 460
Регистрация: 15.11.2014
Сообщений: 5,847
Завершенные тесты: 1
16.07.2016, 16:17     Friend declaration construction #8
Цитата Сообщение от Nosey Посмотреть сообщение
Вам не кажется что это бред?
нет, не кажется.
квалифицированная - значит имеет полное имя с указанием всех спейсов.

http://rextester.com/YOURR59359
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
 
template <typename T> void multiply(T);
 
namespace sample{
 
class Pride
{
    int p;
public:
    friend void ::multiply<int>(int);
    friend void ::multiply<double*>(double*);
};
    
}namespace sample    
 
template <>
void multiply(double*)
{
    Pride pr;
    pr.p = 0; /* тут все нормально */
    (void)pr;
    
}
 
template <>
void multiply(int)
{
    Pride pr;
    pr.p = 0; /* а тут ошибка, то есть эта специализация не является дружественной */
    (void)pr;
}
 
 
int main()
{
    std::cout << "Hello, world!\n";
}

Код
Error(s):
source_file.cpp:19:1: error: expected ‘{’ before ‘template’
 template <>
 ^
source_file.cpp:20:22: error: ‘multiply’ is not a template function
 void multiply(double*)
                      ^
source_file.cpp:29:18: error: ‘multiply’ is not a template function
 void multiply(int)
                  ^
source_file.cpp: In function ‘int sample::main()’:
source_file.cpp:40:1: warning: no return statement in function returning non-void [-Wreturn-type]
 }
 ^
source_file.cpp: At global scope:
source_file.cpp:40:1: error: expected ‘}’ at end of input

дружественная функция, определение которой описано в теле класса не имеет к этому никакого отношения

Добавлено через 55 секунд
Цитата Сообщение от avgoor Посмотреть сообщение
Вы не правильно поняли.
Вот так можно:
квалифицированная - значит имеет полное имя с указанием всех спейсов.
дружественная функция,
определение которой описано в теле класса,
не имеет к этому никакого отношения

Добавлено через 1 минуту
получается, что книга не врет.
но почему то не работает ...
avgoor
884 / 519 / 112
Регистрация: 05.12.2015
Сообщений: 1,464
16.07.2016, 16:22     Friend declaration construction #9
Цитата Сообщение от hoggy Посмотреть сообщение
дружественная функция,
определение которой описано в теле класса,
не имеет к этому никакого отношения
Да ну?
Цитата Сообщение от hoggy Посмотреть сообщение
вот что я нашел в стандарте:
11.3 Friends
6 A function can be defined in a friend declaration of a class if and only if the class is a non-local class (9.8),
the function name is unqualified, and the function has namespace scope.
если я правильно все понял,
Что такое definition и declaration помните?
hoggy
6437 / 2655 / 460
Регистрация: 15.11.2014
Сообщений: 5,847
Завершенные тесты: 1
16.07.2016, 16:27     Friend declaration construction #10
Цитата Сообщение от avgoor Посмотреть сообщение
Что такое definition и declaration помните?
хотите сказать, что неквалифицированными являются только те,
что определены в теле класса?

ну ок, тогда почему не работает код из #8,
и как заставить его работать?
avgoor
884 / 519 / 112
Регистрация: 05.12.2015
Сообщений: 1,464
16.07.2016, 16:31     Friend declaration construction #11
hoggy, Я хочу сказать что ваша цитата относится к определению функций в объявлении друзей и ни к чему другому.
Nosey
1346 / 397 / 107
Регистрация: 22.10.2014
Сообщений: 861
Завершенные тесты: 2
16.07.2016, 16:38     Friend declaration construction #12
Цитата Сообщение от hoggy Посмотреть сообщение
ну ок, тогда почему не работает код из #8,
и как заставить его работать?
Написать этот код на С++ , т.е. посмотреть на код, на ошибки и проставить где надо комментарии и пространства имён :
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
 
template <typename T> void multiply(T);
 
namespace sample{
 
class Pride
{
    int p;
public:
    friend void ::multiply<int>(int);
    friend void ::multiply<double*>(double*);
};
    
}//namespace sample    
 
template <>
void multiply(double*)
{
    sample::Pride pr;
    pr.p = 0; /* тут все нормально */
    (void)pr;
    
}
 
template <>
void multiply(int)
{
    sample::Pride pr;
    pr.p = 0; /* а тут ошибка, то есть эта специализация не является дружественной */
    (void)pr;
}
 
 
int main()
{
    std::cout << "Hello, world!\n";
}

Не по теме:

hoggy, Простите, но вы что-то сегодня курили али пили?

ASCII
90 / 62 / 10
Регистрация: 15.12.2013
Сообщений: 399
Завершенные тесты: 2
16.07.2016, 17:06  [ТС]     Friend declaration construction #13
Nosey,
Цитата Сообщение от Nosey Посмотреть сообщение
— if the name of the friend is a qualified or unqualified template-id, the friend declaration refers to a
specialization of a function template, otherwise
— if the name of the friend is a qualified-id and a matching non-template function is found in the specified
class or namespace, the friend declaration refers to that function, otherwise,
— if the name of the friend is a qualified-id and a matching function template is found in the speci-
fied class or namespace, the friend declaration refers to the deduced specialization of that function
template (14.8.2.6), otherwise,
— the name shall be an unqualified-id that declares (or redeclares) an ordinary (non-template) function.
1) Если имя друга квалифицированный или не квалифицированный template-id ( name_of_function<type1, type2> ), то объявление друга ссылается на специализацию шаблона функции

Тут вроде все понятно, тут говорится про template-id, то есть с указанием угловых скобок

2) Если имя друга квалифицированный идентификатор и соответствует не шаблонной функции в указанном классе или пространстве
имен (как тут правильней перевести?)
, объявление друга ссылается на функцию (обычную)

3) Если имя друга квалифицированный идентификатор и соответствует найденной шаблонной функции в указанном классе или
пространстве имен, объявление друга ссылается на выведенную специализацию шаблона того шаблона функции

4) в противном случае имя должно быть неквалифицированным идентификатором, которое объявляет обычно не шаблонную функцию.

Что это все значит??? Перевести это одно, а вот правильно понять - другое...

Добавлено через 21 минуту
А действительно третее правило не понятно. Говорится, что если квалифицированное имя соответствует шаблону, то дружественность ссылается на специализацию шаблона (ее инстанциированную версию для указанного типа). Однако почему тогда пример не работает? Не пойму чет
Nosey
1346 / 397 / 107
Регистрация: 22.10.2014
Сообщений: 861
Завершенные тесты: 2
16.07.2016, 17:07     Friend declaration construction #14
Цитата Сообщение от ASCII Посмотреть сообщение
Если имя друга квалифицированный идентификатор и соответствует не шаблонной функции в указанном классе или пространстве
имен (как тут правильней перевести?), объявление друга ссылается на функцию (обычную)
Вы правильно перевели, разве что при чтении вами выделенного текста "указанном классе или пространстве имен" вы уже забыли что "имя друга квалифицированный". Т.е. если нашлась функция по "указанной квалификации", а это не просто жопой на клавиатуру сели

Самый главный вопрос, что означает в 3-ем пункте "deduced specialization of that function template", а точнее почему компилятор кладет болт на в последующем определенную специализацию. И еще больший вопрос, а почему же он не кладёт болт в первом пункте.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
16.07.2016, 17:08     Friend declaration construction
Еще ссылки по теме:

Friend Function - C++
Я не очень понимаю как пользаватса Friend функцыей Class.h #include &lt;stdio.h&gt; #include &quot;iostream&quot; using namespace std; ...

friend классы - C++
Доброго времени суток форумчани. Вот потихоньку учу C++, добрался до дружественных функций и классов. Вроде бы все ясно, но все равно не...

класс Friend - C++
Подскажите в каких случаях лучше использовать класс friend? Известно что класс friend нарушает принцип инкапсуляции, так почему же мы его...

Friend и Static - C++ Builder
Здравсвуйте программисты! Изучаю про классы. В теме из книги встречаются постоянно операторы friend и static . Подскажите пожалуйста,как...

Friend класса - C++
#include &lt;iostream&gt; class assoc { struct pair { char* name; int val; }; int free;


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
hoggy
6437 / 2655 / 460
Регистрация: 15.11.2014
Сообщений: 5,847
Завершенные тесты: 1
16.07.2016, 17:08     Friend declaration construction #15
Цитата Сообщение от avgoor Посмотреть сообщение
Я хочу сказать что ваша цитата относится к определению функций в объявлении друзей и ни к чему другому.
я уже понял.
спасибо.

Цитата Сообщение от Nosey Посмотреть сообщение
Простите, но вы что-то сегодня курили али пили?
твою ж заногу!
блин...

надо ж было так лопухнуццо
я не спал две ночи уже)
видимо внимание рассеялось
Yandex
Объявления
16.07.2016, 17:08     Friend declaration construction
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru