Форум программистов, компьютерный форум, киберфорум
Наши страницы

C++

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

Friend declaration construction - C++

16.07.2016, 04:27. Просмотров 1132. Ответов 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; /* а тут ошибка, то есть эта специализация не является дружественной */
}
Почему так?
0
Миниатюры
Friend declaration construction  
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
16.07.2016, 04:27
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Friend declaration construction (C++):

friend указатель - C++
Есть ли что-то типа этого в стандарте: class A { protected: double a; public: typedef double (*td) (double x); td a; ...

Friend функции, определенные в теле класса - C++
Всем привет! Непонятна логика, которой руководствуются компиляторы. Рассмотрим код: #include &lt;iostream&gt; struct A{...

Ошибки "Declaration syntax error" и "Multiple declaration" при компиляции проекта - C++ Builder
Optimalnost_Unit.cpp(6): E2141 Declaration syntax error Optimalnost_Unit.cpp(7): E2238 Multiple declaration for 'Image' ...

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

Некомпилируется при объявлении friend функции - C++ Builder
Всем доброго времени суток! Может кто-нибудь объяснить почему данный код компилится: #define DEF struct DEF str1 { ...

Declaration terminated incorrectly - C++ Builder
Помогите у меня две ошибки в коде, не могу понять в чем дело: перед 1-ым и 2-ым if-ом...

36
hoggy
6691 / 2873 / 493
Регистрация: 15.11.2014
Сообщений: 6,465
Завершенные тесты: 1
16.07.2016, 05:44 #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);
то компилятору явно указывается,
что друг - специализация шаблона под конкретный параметр.
он уже не сможет спутать такой синтаксис с не шаблонной функцией,
и все работает как часы.
1
ASCII
90 / 63 / 10
Регистрация: 15.12.2013
Сообщений: 407
Завершенные тесты: 2
16.07.2016, 14:19  [ТС] #3
hoggy, я убрал определение обычной функции, но оставил
C++
1
friend void ::multiply(int);
Тем не менее ошибка. То есть можно сделать вывод, что в книге ошибка? В частности второе правило?
0
hoggy
6691 / 2873 / 493
Регистрация: 15.11.2014
Сообщений: 6,465
Завершенные тесты: 1
16.07.2016, 15:04 #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.
если я правильно все понял,
то дружественные функции не могут быть квалифицированы.
(иметь полное имя)

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

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

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

C++
1
friend void ::multiply(void*);
Не qualified name?
Надо покопаться в стандарте
0
Nosey
1349 / 400 / 107
Регистрация: 22.10.2014
Сообщений: 863
Завершенные тесты: 2
16.07.2016, 15:35 #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();
}
2
avgoor
915 / 550 / 119
Регистрация: 05.12.2015
Сообщений: 1,531
16.07.2016, 15:54 #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 квалифицировать - то нельзя.
1
hoggy
6691 / 2873 / 493
Регистрация: 15.11.2014
Сообщений: 6,465
Завершенные тесты: 1
16.07.2016, 16:17 #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 минуту
получается, что книга не врет.
но почему то не работает ...
0
avgoor
915 / 550 / 119
Регистрация: 05.12.2015
Сообщений: 1,531
16.07.2016, 16:22 #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 помните?
1
hoggy
6691 / 2873 / 493
Регистрация: 15.11.2014
Сообщений: 6,465
Завершенные тесты: 1
16.07.2016, 16:27 #10
Цитата Сообщение от avgoor Посмотреть сообщение
Что такое definition и declaration помните?
хотите сказать, что неквалифицированными являются только те,
что определены в теле класса?

ну ок, тогда почему не работает код из #8,
и как заставить его работать?
0
avgoor
915 / 550 / 119
Регистрация: 05.12.2015
Сообщений: 1,531
16.07.2016, 16:31 #11
hoggy, Я хочу сказать что ваша цитата относится к определению функций в объявлении друзей и ни к чему другому.
1
Nosey
1349 / 400 / 107
Регистрация: 22.10.2014
Сообщений: 863
Завершенные тесты: 2
16.07.2016, 16:38 #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, Простите, но вы что-то сегодня курили али пили?

1
ASCII
90 / 63 / 10
Регистрация: 15.12.2013
Сообщений: 407
Завершенные тесты: 2
16.07.2016, 17:06  [ТС] #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 минуту
А действительно третее правило не понятно. Говорится, что если квалифицированное имя соответствует шаблону, то дружественность ссылается на специализацию шаблона (ее инстанциированную версию для указанного типа). Однако почему тогда пример не работает? Не пойму чет
0
Nosey
1349 / 400 / 107
Регистрация: 22.10.2014
Сообщений: 863
Завершенные тесты: 2
16.07.2016, 17:07 #14
Цитата Сообщение от ASCII Посмотреть сообщение
Если имя друга квалифицированный идентификатор и соответствует не шаблонной функции в указанном классе или пространстве
имен (как тут правильней перевести?), объявление друга ссылается на функцию (обычную)
Вы правильно перевели, разве что при чтении вами выделенного текста "указанном классе или пространстве имен" вы уже забыли что "имя друга квалифицированный". Т.е. если нашлась функция по "указанной квалификации", а это не просто жопой на клавиатуру сели

Самый главный вопрос, что означает в 3-ем пункте "deduced specialization of that function template", а точнее почему компилятор кладет болт на в последующем определенную специализацию. И еще больший вопрос, а почему же он не кладёт болт в первом пункте.
0
hoggy
6691 / 2873 / 493
Регистрация: 15.11.2014
Сообщений: 6,465
Завершенные тесты: 1
16.07.2016, 17:08 #15
Цитата Сообщение от avgoor Посмотреть сообщение
Я хочу сказать что ваша цитата относится к определению функций в объявлении друзей и ни к чему другому.
я уже понял.
спасибо.

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

надо ж было так лопухнуццо
я не спал две ночи уже)
видимо внимание рассеялось
0
16.07.2016, 17:08
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
16.07.2016, 17:08
Привет! Вот еще темы с ответами:

Declaration Syntax Error - C++ Builder
Вечер добрый. При компиляции, выдаёт ошибку Unit1.cpp(93): E2141 Declaration syntax error. В чём именно может быть проблема?...

Ошибка Multiple declaration for - C++ Builder
Всем привет. Ребята проблема такая. Я (конечно не сам мне помогли) к проекту прикрутил сорцы от 7z (для распаковки архивов). Все...

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

Почему friend ostrem& operator <<(ostream& outs, const Rational&); - invalid function declaration? - C++
Пытаюсь скомпилировать программу пишет friend ostrem&amp; operator &lt;&lt;(ostream&amp; outs, const Rational&amp;); - invalid function declaration. ...


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

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Опции темы

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