#include <iostream>
using namespace std;
namespace A {
template <typename T>
void foo(T*)
{
cout << "void foo(T*)\n";
}
};
class B {
public:
friend void A::foo<>(B*);
private:
int b_;
};
int main()
{
B b;
foo(&b);
return 0;
}
который нормально компилируется, но почему-то не работает так, как ожидается. Точнее, функция foo фактически не вызывается.
Вопрос: если это пример Argument Dependent Name Lookup, то почему функция не вызывается, если это не ADNL, то почему нету ошибки компиляции?
Здравствуйте, Антибиотик, Вы писали:
А>имеется следующий код: А>который нормально компилируется,
VC2005 (другими не пробовал), но не gcc и не comeau.
G++ 3.4.4, например:
t.cpp:15: error: `void A::foo(B*)' should have been declared inside `A'
t.cpp: In function `int main()':
t.cpp:23: error: `foo' undeclared (first use this function)
t.cpp:23: error: (Each undeclared identifier is reported only once for each function it appears in.)
А> но почему-то не работает так, как ожидается. Точнее, функция foo фактически не вызывается.
Баг VC.
Попросту не сгенерировал никакой код.
А>Вопрос: если это пример Argument Dependent Name Lookup, то почему функция не вызывается, если это не ADNL, то почему нету ошибки компиляции?
Кстати, обычно это называют ADL (argument dependent lookup), без ...name... — если захочешь в гугле искать, чтоб проблем не было.
Здравствуйте, Антибиотик, Вы писали:
А>Вопрос: если это пример Argument Dependent Name Lookup, то почему функция не вызывается, если это не ADNL, то почему нету ошибки компиляции?
Да, раз уж на то пошло, это не ADL.
ADL будет в том случае, если В будет в А:
namespace A {
template <typename T>
void foo(T*p)
{
cout << "void foo(T*)\n";
}
class B {
public:
template<typename T> friend void foo(T*);
private:
int b_;
};
}
int main()
{
A::B b;
foo(&b);
}
Здравствуйте, Антибиотик, Вы писали:
1. не компилируется, так как foo не найдена, надо A::foo — так всё работает.
2. не понял при чём тут B.
А>имеется следующий код: А>
А>который нормально компилируется, но почему-то не работает так, как ожидается. Точнее, функция foo фактически не вызывается. А>Вопрос: если это пример Argument Dependent Name Lookup, то почему функция не вызывается, если это не ADNL, то почему нету ошибки компиляции?
Здравствуйте, Антибиотик, Вы писали:
А>Вопрос: если это пример Argument Dependent Name Lookup, то почему функция не вызывается, если это не ADNL, то почему нету ошибки компиляции?
1) Синтаксис объявления друга неправильный, должно быть:
Здравствуйте, The_Thing, Вы писали:
T_T>Здравствуйте, Антибиотик, Вы писали: T_T>1. не компилируется, так как foo не найдена, надо A::foo — так всё работает. T_T>2. не понял при чём тут B.
1. используется компилятор Microsoft Visual C++ 2008 Express, в нем все нормально компилируется
2. это упрощенный пример более сложного кода, суть в том, что функция foo вызывается с аргументом типа B. Чтобы было понятнее, пусть функция foo выглядит так:
J>>2) GCC 3.4.6 компилирует и всё работает
J>>Что за компилятор?
К>Твою поправку не компилируют VC 2005 и 2008. Да, микрософт умеет удивлять
ну, может, это бага гцц
А если заменить В на Т? тогда перестанет компилировать вызов, правда, потому что это не АDL все равно
Зато должно начать компилировать объявление френда
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, Антибиотик, Вы писали:
А>>Вопрос: если это пример Argument Dependent Name Lookup, то почему функция не вызывается, если это не ADNL, то почему нету ошибки компиляции? J>Да, раз уж на то пошло, это не ADL. J>ADL будет в том случае, если В будет в А:
J>
Да, согласен, что пример из первого поста на ADL не тянет ))
В первом посте фишка в том, что мне не нужны френдами абсолютно все функции foo, а нужна френдом только ее специализация для B.
Судя по всему, это на самом деле бага VC. Ну что же, идем на MS Connect ))
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, Антибиотик, Вы писали:
А>>Вопрос: если это пример Argument Dependent Name Lookup, то почему функция не вызывается, если это не ADNL, то почему нету ошибки компиляции? J>Да, раз уж на то пошло, это не ADL. J>ADL будет в том случае, если В будет в А:
Ну и не только в этом случае, а во всех случаях, когда А становится ассоциированным (3.4.2/2) с В, напирмер, так:
J>
Согласен, что данный код будет работать и в студии, если при вызове foo указать пространство имен. Причина создания данной темы состоит в том, почему VC кушает вызов foo и без неймспейса.
Здравствуйте, Антибиотик, Вы писали:
А>Согласен, что данный код будет работать и в студии, если при вызове foo указать пространство имен. Причина создания данной темы состоит в том, почему VC кушает вызов foo и без неймспейса.
Может и не баг, надо стандарт глянуть раздел дружественных функций и посмотреть, что там сказано про пространство имен (может и ничего не сказано, тогда баг).
Что-то тут не так. Как объявляемая функция зависит от T? И если не зависит, то почему тут шаблон?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, Антибиотик, Вы писали:
А>>Вопрос: если это пример Argument Dependent Name Lookup, то почему функция не вызывается, если это не ADNL, то почему нету ошибки компиляции?
J>1) Синтаксис объявления друга неправильный, должно быть: J>
14.8.1/2:
[q]A template argument list may be specified when referring to a specialization of a function template
— when a function is called,
— when the address of a function is taken, when a function initializes a reference to function, or when a
pointer to member function is formed,
— in an explicit specialization,
— in an explicit instantiation, or
— in a friend declaration.
Trailing template arguments that can be deduced (14.8.2) may be omitted from the list of explicit templatearguments. If all of the template arguments can be deduced, they may all be omitted; in this case, the empty template argument list <> itself may also be omitted.
Антибиотик:
А>Вопрос: если это пример Argument Dependent Name Lookup, то почему функция не вызывается, если это не ADNL, то почему нету ошибки компиляции?
Текущий стандарт недостаточно чётко описывает, какие именно friend-объявления могут рассматриваться при аргументо-зависимом поиске. По этому поводу есть defect report — DR 143. Если брать за основу уточнённые формулировки, то относительно данного кода можно сказать, что через ADL foo искаться не будет.
E>Что-то тут не так. Как объявляемая функция зависит от T? И если не зависит, то почему тут шаблон?
Это опечатка, должно было быть Т
Я не понял, что Антибиотик хотел именно специализацию сделать френдом.
А так — это просто шаблонная функция, у которой параметр шаблона не фигурирует в аргументах (но используется где-то внутри, например), это совершенно валидно.
Ну и эта функция, я думаю, инжектируется в объемлющее В пространство имен, хотя настаивать на этом не буду — дело с инжекцией традиционно темное.
Другое дело, что в таком случае получается не совсем та функция. Которая вообще не определена
Так что то ,что он вызывает нашу функци — это, наверное, баг этой версии гцц.
Здравствуйте, Антибиотик, Вы писали:
А>В первом посте фишка в том, что мне не нужны френдами абсолютно все функции foo, а нужна френдом только ее специализация для B.
jazzer:
J>А так — это просто шаблонная функция, у которой параметр шаблона не фигурирует в аргументах (но используется где-то внутри, например), это совершенно валидно.
Это корректно только если в A действительно присутствует такая функция:
namespace A
{
template <typename T>
void foo(T*) {}
}
struct B
{
template<typename T>
friend void A::foo(B *);
};
то здесь функции разные и такая программа будет ill-formed — см. 8.3/1:
When the declarator-id is qualified, the declaration shall refer to a previously declared member of the class or namespace to which the qualifier refers, and the member shall not have been introduced by a using-declaration in the scope of the class or namespace nominated by the nested-name-specifier of the declarator-id.
J>Ну и эта функция, я думаю, инжектируется в объемлющее В пространство имен.
Такого точно нету. Friend-объявление может добавить новый член в пространство имён только если сущность, объявляемая другом, обозначена неквалифицированным именем, однако новое имя в пространство имён этом не вводится. См. 7.3.1.2/3:
If a friend declaration in a non-local class first declares a class or function [footnote 83: this implies that the name of the class or function is unqualified] the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by simple name lookup until a matching declaration is provided in that namespace scope (either before or after the class declaration 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).
(случай, когда friend-объявление находится в локальном классе, описан в 11.4/9).
struct X
{
friend void f(X) {}
friend void f(int) {}
};
int main()
{
f(X()); // well-formed: f не находится через unqualified lookup, но находится через ADL
f(0); // ill-formed: f не находится ни через unqualified lookup, ни через ADL
}
Здравствуйте, Николай Ивченков, Вы писали:
НИ>Это корректно только если в A действительно присутствует такая функция: НИ>... НИ>то здесь функции разные и такая программа будет ill-formed — см. 8.3/1:
Ну, значит, это баг GCC.
Я не проверял на более новой версии, версия 3.4.6 — довольно-таки старая