Вопрос такой: зачем в ADL включаются пространства типов, которыми инстанцированы шаблоны?
Я что-то не могу придумать ни одного разумного примера, только неразумные и вредные.
Вот пример, как это проявляется:
namespace x
{
template <typename T>
int distance( T b, T e );
struct item {};
}
namespace y
{
template <typename T>
int distance( T b, T e );
template <typename T>
struct i {};
template <typename T>
struct c
{
i<T> begin();
i<T> end();
int size() { return distance(begin(), end()); }
};
}
void test()
{
y::c<x::item>().size();
}
Комо ругается так:
"ComeauTest.c", line 23: error: more than one instance of function template"y::distance" matches the argument list, the choices that match are:
function template"int y::distance(T, T)"
function template"int x::distance(T, T)"
The argument types that you used are: (y::i<x::item>, y::i<x::item>)
int f() { return distance(begin(), end()); }
^
detected during instantiation of "int y::c<T>::f() [with T=x::item]"
at line 29
В моем случае это проявилось очень весело — был класс A, унаследованный от boost::mpl::empty_base в десятом поколении, и я создал std::list<A> — и не смог позвать size(), потому что в boost::mpl есть своя distance
Не, ну мне кажется, что придумать случай, когда надо легко исходя буквально из твоих примеров:
namespace U
{
template<class T>
class i
{
/////
};
}
namespace A
{
class B{};
void fun(const U::i<B> &);//хочу, чтобы ее нашли!!!
}
namespace U
{
template<class T>
class O
{
public:
O(){i<T> a; fun(a);}
};
}
int main()
{
U::O<A::B> a;
}
Of course, the code must be complete enough to compile and link.
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>>Не, ну мне кажется, что придумать случай, когда надо легко исходя буквально из твоих примеров:
J>ты реалистичный пример приведи
А что для тебя реалистично? Если я дурацкие имена заменю именами из стандартной библиотеки, это сделает пример реалистичным или нет?
Of course, the code must be complete enough to compile and link.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>Здравствуйте, jazzer, Вы писали:
J>>Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>>>Не, ну мне кажется, что придумать случай, когда надо легко исходя буквально из твоих примеров:
J>>ты реалистичный пример приведи
L_L>А что для тебя реалистично? Если я дурацкие имена заменю именами из стандартной библиотеки, это сделает пример реалистичным или нет?
я имею в виду, чтоб эта фича решала какую-то более-менее реальную полезную задачу.
потому что в общем случае мы плодим кучу вложенных пространств имен для того, чтобы спрятать нечто и то, что с ним связано, а получается, что стоит проинстанцировать этим нечто какой-нть шаблон — и этот несчастный шаблон автоматически получает доступ ко всем потрохам, чего нам совершенно не нужно, нам бы как раз хотелось, чтоб такое происходило только по явному указанию.
Ведь идея какая — для внешнего мира шаблон класса не имеет связи с тем, чем его инстанцировали, если не предприняты специальные меры (например, шаблон наследуется от своего аргумента). Т.е. std::auto_ptr<int> и int — это совершенно несвязанные типы. И с какого перепугу вдруг везде, где я вызываю функции с std::auto_ptr<X::y>, должны дергаться еще и функции из совершенно левого пространства X — мне лично непонятно.
Причем обычно ты на это напарываться не будешь, потому что типы разные, но вот стоит завестись шаблонам, как в моем случае — и все, пиши пропало. А ведь, казалось бы, все спрятал во вложенных пространствах имен.
Т.е. унаследовался от чего-нть в boost или в std — и сразу получил из них в нагрузку кучу шаблонов к твоему ADL, безо всякого using namespace std.
Может быть, именно для защиты от этого boost::noncopyable сидит в своем пространстве:
J>потому что в общем случае мы плодим кучу вложенных пространств имен для того, чтобы спрятать нечто и то, что с ним связано, а получается, что стоит проинстанцировать этим нечто какой-нть шаблон — и этот несчастный шаблон автоматически получает доступ ко всем потрохам, чего нам совершенно не нужно, нам бы как раз хотелось, чтоб такое происходило только по явному указанию.
J>Ведь идея какая — для внешнего мира шаблон класса не имеет связи с тем, чем его инстанцировали, если не предприняты специальные меры (например, шаблон наследуется от своего аргумента). Т.е. std::auto_ptr<int> и int — это совершенно несвязанные типы. И с какого перепугу вдруг везде, где я вызываю функции с std::auto_ptr<X::y>, должны дергаться еще и функции из совершенно левого пространства X — мне лично непонятно.
J>Причем обычно ты на это напарываться не будешь, потому что типы разные, но вот стоит завестись шаблонам, как в моем случае — и все, пиши пропало. А ведь, казалось бы, все спрятал во вложенных пространствах имен.
Наверное, люди придумавшие АДЛ на это сказали бы "ну, мы вообще-то хотели как лучше, а получилось .... как всегда"
Of course, the code must be complete enough to compile and link.
Здравствуйте, jazzer, Вы писали:
J>Приветствую всех!
J>Вопрос такой: зачем в ADL включаются пространства типов, которыми инстанцированы шаблоны? J>Я что-то не могу придумать ни одного разумного примера, только неразумные и вредные.
namespace my
{
struct My {};
ostream& operator << (ostream&, const My &)
{
...
}
}
...
my::My m;
std::cout << m;
#include <vector>
namespace N
{
struct X { };
template<typename T>
int* operator+( T , unsigned )
{
static int i ; return &i ; /* just to stub in the function body */
}
}
int main()
{
std::vector< N::X > v(5);
v[ 0 ];
}
// An extract from libstdc++ 3.2, distilled and editednamespace __gnu_cxx
{
template<typename T> class __normal_iterator
{
public:
__normal_iterator operator+(const long& __n) const {…}
};
}
namespace std
{
template <class T> class vector
{
public:
typedef __gnu_cxx::__normal_iterator<T> iterator;
iterator operator[](unsigned __n) { return iterator() + __n; }
};
}
In this case, we might argue that this is a problem with ADL. Under the current rules N is an associated
namespace of __normal_iterator<N::X>, so N::operator+<N::X>( unsigned ) should be considered,
and it happens to be a better match. Yes, the library implementer could have written the code
more defensively. But what about a library that is written to avoid ADL? From Dinkumware 3.13:
//An extract from Dinkumware 3.13, distilled and editednamespace std
{
template<class T> struct _Ranit { };
template<class T> class vector
{
public:
class iterator : public _Ranit<T>
{
public:
iterator operator+(int) const { return iterator(); }
};
iterator operator[](unsigned _Pos) { return iterator()+_Pos; }
};
}
Compiling this code under various compilers produces various results. This is a case of “Compiler
Bugs Bite,” because N is not an associated namespace of std::vector<N::X>::iterator (the _Ranit<T>
base doesn’t matter). But all shipping versions I tried of Gnu g++ (up to 3.4.3) and Microsoft VC++ (up
to 7.1) do incorrectly find it. Comeau 4.3.3 and the current beta of Microsoft VC++ 8 are two compilers
that correctly do not find it.
Здравствуйте, jazzer, Вы писали:
J>В моем случае это проявилось очень весело — был класс A, унаследованный от boost::mpl::empty_base в десятом поколении, и я создал std::list<A> — и не смог позвать size(), потому что в boost::mpl есть своя distance
В общем, поскольку мой случай был связан с STL, я закинул баг репорт в STLport (основываясь на 17.4.1.1/3), вроде, они согласились его фиксить.
17.4.1.1/3
Whenever a name x defined in the standard library is mentioned, the name x is assumed to be fully qualified as ::std::x, unless explicitly described otherwise. For example, if the Effects section for library function F is described as calling library function G, the function ::std::G is meant.