ADL и друг инъекция - PullRequest
       27

ADL и друг инъекция

6 голосов
/ 03 сентября 2010

Рассмотрим этот код:

template <int N>
struct X
{
 friend void f(X *) {}
};

int main()
{
 f((X<0> *)0); // Error?
}

компиляторы, похоже, сильно не согласны.(MSVC08 / 10 говорит «нет», GCC <4.5 говорит «да», но 4.5 говорит «нет», вс 5.1 говорит «да», Intel 11.1 тоже говорит «да», но Comeau говорит «нет» (оба EDG)).- Полное руководство ": </p>

... предполагается, что вызов, включающий поиск друзей в ассоциированных классах, фактически приводит к созданию экземпляра класса ... Хотя это было явно предназначено теми, ктонаписал стандарт C ++, он не четко прописан в стандарте.

Я не смог найти соответствующий раздел в стандарте.Любая ссылка?

Рассмотрите этот вариант:

template <int N>
struct X
{
 template <int M>
 friend void f(X<M> *) {}
};

template <>
struct X<0>
{
};

int main()
{
 X<1>();
 f((X<0> *)0); // Error?
}

Ключевой вопрос здесь заключается в том, должна ли жизнеспособная функция, введенная X<1>, быть видимой во время ADL для X<0>?Они связаны?Все компиляторы, упомянутые выше, принимают этот код, кроме Comeau, который принимает его только в расслабленном режиме.Не уверен, что стандарт говорит об этом.

Что вы думаете об этом?

1 Ответ

4 голосов
/ 03 сентября 2010

Стандарт говорит в 14.7.1/4

Специализация шаблона класса неявно создается, если тип класса используется в контексте, который требует полностью определенного типа объекта, или если полнота типа класса влияет на семантику программы; в частности, если выражение, тип которого является специализацией шаблона класса, участвует в разрешении перегрузки, преобразовании указателя, преобразовании указателя в член, неявно создается экземпляр специализации шаблона класса (3.2);

Обратите внимание, что Vandervoorde сделал отчет о проблеме здесь , и комитет нашел

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

Для вашего второго случая - вам нужно рассмотреть связанные классы и пространства имен аргумента f(X<0>*). Это так, поскольку это указатель на специализацию шаблона класса (обратите внимание, что «идентификатор шаблона» ниже не совсем корректен - C ++ 0x исправил это, чтобы использовать правильный термин), а также указатель на класс (это запутанное разделение также исправлено в C ++ 0x - эти два случая перечислены в одном пункте).

  • Если T является идентификатором шаблона, то связанные с ним пространства имен и классы являются пространством имен, в котором находится шаблон. определены; [... много шума ...]

  • Если T является типом класса (включая объединения), его ассоциированными классами являются: сам класс; класс, членом которого он является, если таковой имеется; и его прямые и косвенные базовые классы. Связанные пространства имен - это пространства имен, в которых определены связанные классы.

Итак, подведем итог: у нас есть связанные классы X<0>, а связанные пространства имен являются глобальным пространством имен. Теперь видимые функции друзей:

  • Любые дружественные функции области имен, объявленные в связанных классах, видимы в своих соответствующих пространствах имен, даже если они не видны во время обычного поиска

В X<0> не объявлена ​​функция-друг, поэтому объявление функции-друга не видно при просмотре глобального пространства имен. Обратите внимание, что X<0> - это совершенно другой тип класса, чем X<1>. Неявная реализация X<1>, которую вы там выполняете, не влияет на этот вызов - он просто добавляет невидимое имя в глобальное пространство имен, которое ссылается на функцию друга класса X<1>.

...