функция друга, определенная внутри класса шаблона - PullRequest
0 голосов
/ 29 января 2019

Функция друга с именем test () определена внутри класса шаблона A:

template <typename T> class A {
public:
    friend void cs() {/* code */}
}

Другой класс наследует от класса шаблона A:

class B : public A<B> {}

В основной функции мне не удалосьчтобы вызвать cs (), компилятор не сможет увидеть его объявление, если я не предоставлю объявление функции в глобальной области видимости:

int main(){
    cs()
}

Но все иначе, когда cs принимает класс шаблона T в качестве аргумента:

template <typename T> class A{
public:
    friend void cs(const T& t) {}
}

Теперь функция cs () может быть успешно вызвана в главной функции без декальтрации:

int main(){
    B b;
    cs(b);
}

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

Ответы [ 3 ]

0 голосов
/ 29 января 2019

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

Вы описываете поиск, зависящий от аргумента, здесь.И это именно то, как cs найдено.

cs находится в том же пространстве имен, в котором определено A<B>, то есть пространство имен и область действия A.

ДляВ целях ADL реализация собирает «связанные пространства имен».К ним также относятся пространства имен базовых классов.

[basic.lookup.argdep]

2.2 Если T является типом класса(включая союзы), его ассоциированные классы: сам класс;класс, членом которого он является, если таковой имеется;и его прямые и косвенные базовые классы.Связанные с ним пространства имен являются внутренним пространством имен связанных классов.Кроме того, если T является специализацией шаблона класса, связанные с ним пространства имен и классы также включают в себя: пространства имен и классы, связанные с типами аргументов шаблона, предоставляемых для параметров типа шаблона (исключая параметры шаблона шаблона);пространства имен, членами которых являются любые аргументы шаблона;и классы, членами которых являются любые шаблоны-члены, используемые в качестве аргументов шаблона.[Примечание: нетипичные аргументы шаблона не вносят вклад в набор связанных пространств имен.- конец примечания]

0 голосов
/ 29 января 2019

Обратите внимание, что имя cs, введенное декларацией друга , невидимо для обычного поиска имени;вот почему 1-й случай завершается неудачно, если вы не предоставите объявление в области имен.

Имя, впервые объявленное в объявлении друга в классе или шаблоне класса X, становится членом внутреннего вложенного пространства имен X, ноне отображается для поиска (кроме поиска, зависящего от аргумента, который учитывает X), если не указано соответствующее объявление в области имен

И имя cs успешно найдено во 2-м случае из-за ADL ;Вы задаете параметр для cs.

Поиск, зависящий от аргумента, также известный как ADL или поиск по Кенигу, представляет собой набор правил для поиска неквалифицированных имен функций в выражениях вызова функций,включая неявные вызовы функций перегруженным операторам.Эти имена функций ищутся в пространствах имен их аргументов в дополнение к областям и пространствам имен, рассматриваемым при обычном поиске неквалифицированных имен.

И

Так, какая область точноопределено cs ()?

Имя cs становится членами самого внутреннего охватывающего пространства имен A, то есть глобального пространства имен здесь, но оно не видно для обычного поиска имени.

0 голосов
/ 29 января 2019

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

Да, это называется ADL.Когда вы пишете cs(b), компилятор ищет функцию с именем cs.Он не может найти ничего, что происходит в вашем первом примере.

Но теперь, когда cs принимает b, компилятор также может искать в области действия b функцию с именемcs.Это не было возможно в первом примере, потому что не было никаких параметров!В B он находит void cs(const B&) и использует это.

Так, какая область точно определена cs ()?

В глобальной области видимости, но csпоиск по имени без ADL не виден.

Как возможно, что cs () успешно вызывается во втором случае?

Как объяснено, cs можетможно найти через ADL на B.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...