enabling ADL even with namespace qualification

Dear All, I've put meself in a funny situation. I have a class with an begin() end() members, but I wan't to call boost::begin() boost::end() without the boost:: prefix so ADL is functional. Can that be done? Thanks Thorsten

Thorsten Ottosen wrote:
Dear All,
I've put meself in a funny situation. I have a class with an begin() end() members, but I wan't to call boost::begin() boost::end() without the boost:: prefix so ADL is functional. Can that be done?
At the point of use, bring boost::begin and boost::end into local scope with using declarations. That should hide the versions in class scope. -- Eric Niebler Boost Consulting www.boost-consulting.com

"Eric Niebler" <eric@boost-consulting.com> wrote in message news:4106A244.2020800@boost-consulting.com... | | Thorsten Ottosen wrote: | > Dear All, | > | > I've put meself in a funny situation. I have a class with an begin() end() members, but I wan't to call boost::begin() boost::end() | > without the boost:: prefix so ADL is functional. Can that be done? | > | | At the point of use, bring boost::begin and boost::end into local scope | with using declarations. That should hide the versions in class scope. ok, and how do you do that in an initializer list? :-) -Thorsten

On Wed, 28 Jul 2004 09:24:07 +1000, Thorsten Ottosen wrote:
"Eric Niebler" <eric@boost-consulting.com> wrote in message news:4106A244.2020800@boost-consulting.com... | | Thorsten Ottosen wrote: | > | > I've put meself in a funny situation. I have a class with an begin() | > end() members, but I wan't to call boost::begin() boost::end() | > without the boost:: prefix so ADL is functional. Can that be done? | > | At the point of use, bring boost::begin and boost::end into local scope | with using declarations. That should hide the versions in class scope.
ok, and how do you do that in an initializer list? :-)
You put it into a separate function? template <class T> typename boost::iterator_of<T>::type your_begin(T const& x) { using boost::begin; return begin(x); } template <class T> your_class<T>::your_class(T const& x) : begin_(your_begin(x)) {} boost::iterator_of might not be right for you, but I'm guessing that since you're going to store the result somewhere, you should be able to come up with a reasonable alternative. If you really must do it in the initialiser list, another alternative is to put the class' implementation into a separate namespace. namespace obscure { using boost::begin; template <class T> class your_class { iterator begin_; public: your_class(T const& x) : begin_(begin(x)) {} iterator your_begin(); }; } template <class T> class your_class { obscure::your_class<T> impl_; public: your_class(T const& x) : impl_(x) {} iterator begin() { return impl_.your_begin(); } } So, what's the flaw in the plan? Daniel

"Daniel James" <daniel@calamity.org.uk> wrote in message news:pan.2004.07.28.00.44.38.578992@calamity.org.uk... | On Wed, 28 Jul 2004 09:24:07 +1000, Thorsten Ottosen wrote: | | > "Eric Niebler" <eric@boost-consulting.com> wrote in message | > news:4106A244.2020800@boost-consulting.com... | > | | > | Thorsten Ottosen wrote: | > | > | > | > I've put meself in a funny situation. I have a class with an begin() | > | > end() members, but I wan't to call boost::begin() boost::end() | > | > without the boost:: prefix so ADL is functional. Can that be done? | > | > | > | At the point of use, bring boost::begin and boost::end into local scope | > | with using declarations. That should hide the versions in class scope. | > | > ok, and how do you do that in an initializer list? :-) | | You put it into a separate function? yes, of course...doh. I wasn't thinking last night :-) | So, what's the flaw in the plan? nothing. Thanks! Thorsten

Daniel James wrote:
[many things]
FYI, Thorsten checked in a test case (range/adl_conformance) to check ADL conformance on various compilers before he left for vacation. It's not that this testcase tells us much about the range library, but the results are nevertheless interesting and show that some compilers still have their difficulties! Among these are the (current) Microsoft compiler(s), but also Intel: once again the tests pass on Windows and fail on Linux (one should mean they have different front ends)! If there really is an intention to extend the use of ADL in the boost library, one perhaps should ask Microsoft to fix the issues in VC 8. Stefan

Stefan Slapeta wrote:
Daniel James wrote:
[many things]
FYI, Thorsten checked in a test case (range/adl_conformance) to check ADL conformance on various compilers before he left for vacation.
It's not that this testcase tells us much about the range library, but the results are nevertheless interesting and show that some compilers still have their difficulties! Among these are the (current) Microsoft compiler(s), but also Intel: once again the tests pass on Windows and fail on Linux (one should mean they have different front ends)!
If there really is an intention to extend the use of ADL in the boost library, one perhaps should ask Microsoft to fix the issues in VC 8.
Maybe the following helps to create a more robust version of the idiom, as it doesn't need 'using' at all: #include <iostream> namespace A { namespace detail { template< typename T > void f( const T& ) { std::cout << 1 << std::endl; } template< typename T > void adl_f( const T& x ) { f( x ); } } template< typename T > void f( const T& x ) { detail::adl_f( x ); } } namespace B { class C {}; void f( const C& ) { std::cout << 2 << std::endl; } } int main() { A::f( 42 ); B::C c; A::f( c ); } Regards, Daniel -- Daniel Frey aixigo AG - financial solutions & technology Schloß-Rahe-Straße 15, 52072 Aachen, Germany fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99 eMail: daniel.frey@aixigo.de, web: http://www.aixigo.de The hacks that we write today become the bugs of tomorrow.

Maybe the following helps to create a more robust version of the idiom, as it doesn't need 'using' at all: [snip] I think this won't work afterall. If I put a class into namespace A, I will get ambiguity. namespace A { namespace detail { template< typename T > void f( const T& ) { std::cout << 1 << std::endl; } template< typename T > void adl_f( const T& x ) { f( x ); } } template< typename T > void f( const T& x ) { detail::adl_f( x ); } // this is bad!! struct C {}; } namespace B { class C {}; void f( const C& ) { std::cout << 2 << std::endl; } } int main() { A::f( 42 ); A::C c0; A::f( c0 ); // error! B::C c; A::f( c ); } br Thorsten

Thorsten Ottosen wrote:
Maybe the following helps to create a more robust version of the idiom, as it doesn't need 'using' at all:
[snip]
I think this won't work afterall.
Hm, good point. The only "solution" I could come up with is shown below, but I don't know how portable/robust it is. #include <iostream> namespace A { // For this test, we assume sizeof(char) < sizeof(double) class internal { double dummy; }; char operator,( const internal&, const internal& ); template< typename T > internal f( const T& x ) { if( sizeof( f(x),internal() ) == sizeof( char ) ) { // Non-ADL-implementation std::cout << 1 << std::endl; } else { // ADL-forwarder f( x ); } return internal(); } class C {}; } namespace B { class C {}; void f( const C& ) { std::cout << 2 << std::endl; } } int main() { A::f( 42 ); A::C c0; A::f( c0 ); B::C c; A::f( c ); } Regards, Daniel -- Daniel Frey aixigo AG - financial solutions & technology Schloß-Rahe-Straße 15, 52072 Aachen, Germany fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99 eMail: daniel.frey@aixigo.de, web: http://www.aixigo.de

"Daniel Frey" <daniel.frey@aixigo.de> wrote in message news:cfhteq$piv$1@sea.gmane.org... |Hm, good point. The only "solution" I could come up with is shown below, |but I don't know how portable/robust it is. | | template< typename T > | internal f( const T& x ) | { | if( sizeof( f(x),internal() ) == sizeof( char ) ) { | // Non-ADL-implementation | std::cout << 1 << std::endl; | } | else { | // ADL-forwarder | f( x ); | } | return internal(); | } why do you return an internal here? I mean, weed want to return f(x). br Thorsten

Thorsten Ottosen wrote:
"Daniel Frey" <daniel.frey@aixigo.de> wrote in message news:cfhteq$piv$1@sea.gmane.org...
|Hm, good point. The only "solution" I could come up with is shown below, |but I don't know how portable/robust it is.
| | template< typename T > | internal f( const T& x ) | { | if( sizeof( f(x),internal() ) == sizeof( char ) ) { | // Non-ADL-implementation | std::cout << 1 << std::endl; | } | else { | // ADL-forwarder | f( x ); | } | return internal(); | }
why do you return an internal here? I mean, weed want to return f(x).
But we need to detect which f(x) is choosen in the sizeof. The ADL f(x) won't return internal, thus the operator, isn't applied, thus the sizeof( f(x),internal() ) is not sizeof( char ). How else could you detect which f(x) would be choosen? The above example also "wants" to return void, thus it should work. For non-void return types, the class 'internal' must be more complicated. But maybe someone else has a better (and robust enough) idea how to detect which f(x) would be called... Regards, Daniel -- Daniel Frey aixigo AG - financial solutions & technology Schloß-Rahe-Straße 15, 52072 Aachen, Germany fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99 eMail: daniel.frey@aixigo.de, web: http://www.aixigo.de

Daniel Frey <daniel.frey@aixigo.de> writes:
Thorsten Ottosen wrote:
"Daniel Frey" <daniel.frey@aixigo.de> wrote in message news:cfhteq$piv$1@sea.gmane.org... |Hm, good point. The only "solution" I could come up with is shown below, |but I don't know how portable/robust it is. | | template< typename T > | internal f( const T& x ) | { | if( sizeof( f(x),internal() ) == sizeof( char ) ) { | // Non-ADL-implementation | std::cout << 1 << std::endl; | } | else { | // ADL-forwarder | f( x ); | } | return internal(); | } why do you return an internal here? I mean, weed want to return f(x).
But we need to detect which f(x) is choosen in the sizeof. The ADL f(x) won't return internal, thus the operator, isn't applied, thus the sizeof( f(x),internal() ) is not sizeof( char ). How else could you detect which f(x) would be choosen? The above example also "wants" to return void, thus it should work. For non-void return types, the class internal' must be more complicated.
But maybe someone else has a better (and robust enough) idea how to detect which f(x) would be called...
You can use something like what boost/detail/is_incrementable.hpp is doing, but I think that's basically the same technique you're using. And this seems to be exactly what I was talking about on the NG when I suggested removing ambiguity by detecting whether there's a function that could be found via ADL... or am I missing something? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote in message news:u7js29ae4.fsf@boost-consulting.com... | Daniel Frey <daniel.frey@aixigo.de> writes: | > But maybe someone else has a better (and robust enough) idea how to | > detect which f(x) would be called... | | You can use something like what boost/detail/is_incrementable.hpp is | doing, but I think that's basically the same technique you're using. | And this seems to be exactly what I was talking about on the NG when I | suggested removing ambiguity by detecting whether there's a function | that could be found via ADL... or am I missing something? are this all very complicated compared to what we want to achieve. wouldn't it be better just to stick to the using detail::XX trick and then write on the portability page that for best portability, always include new overloads before the range library. br Thorsten

"Thorsten Ottosen" <nesotto@cs.auc.dk> writes:
"David Abrahams" <dave@boost-consulting.com> wrote in message news:u7js29ae4.fsf@boost-consulting.com... | Daniel Frey <daniel.frey@aixigo.de> writes:
| > But maybe someone else has a better (and robust enough) idea how | > to detect which f(x) would be called... | | You can use something like what boost/detail/is_incrementable.hpp | is doing, but I think that's basically the same technique you're | using. And this seems to be exactly what I was talking about on | the NG when I suggested removing ambiguity by detecting whether | there's a function that could be found via ADL... or am I missing | something?
are this all very complicated compared to what we want to achieve. wouldn't it be better just to stick to the using detail::XX trick and then write on the portability page that for best portability, always include new overloads before the range library.
I don't know what you're suggesting precisely, nor what problem we're trying to solve globally, so I can't answer. Maybe if someone could synthesize this all into a short description it would be easier. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote in message news:ufz6q4qlr.fsf@boost-consulting.com... | "Thorsten Ottosen" <nesotto@cs.auc.dk> writes: | > are this all very complicated compared to what we want to | > achieve. wouldn't it be better just to stick to the using detail::XX | > trick and then write on the portability page that for best | > portability, always include new overloads before the range library. | | I don't know what you're suggesting precisely, nor what problem we're | trying to solve globally, so I can't answer. Maybe if someone could | synthesize this all into a short description it would be easier. We want to find an easy way to enable ADL lookup with qualified syntax and to find an portable implementation of that (perhaps without a using declaration). br Thorsten

"Thorsten Ottosen" <nesotto@cs.auc.dk> writes:
"David Abrahams" <dave@boost-consulting.com> wrote in message news:ufz6q4qlr.fsf@boost-consulting.com... | "Thorsten Ottosen" <nesotto@cs.auc.dk> writes:
| > are this all very complicated compared to what we want to | > achieve. wouldn't it be better just to stick to the using detail::XX | > trick and then write on the portability page that for best | > portability, always include new overloads before the range library. | | I don't know what you're suggesting precisely, nor what problem we're | trying to solve globally, so I can't answer. Maybe if someone could | synthesize this all into a short description it would be easier.
We want to find an easy way to enable ADL lookup with qualified syntax
Not possible, except through a 2-level scheme like Daniel's. In other words, a qualified call will never use ADL directly. It *can* call another function using ADL, of course.
and to find an portable implementation of that (perhaps without a using declaration).
Should be no trouble, I think. That said, I think you were on the right track to a solution. Before we declare victory we should probably discuss the issue of handling lvalue/rvalue arguments to the function that's ultimately called. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote in message news:uu0v5c248.fsf@boost-consulting.com... | "Thorsten Ottosen" <nesotto@cs.auc.dk> writes: | > and to find an portable implementation of that (perhaps without a | > using declaration). | | Should be no trouble, I think. That said, I think you were on the | right track to a solution. yeah maybe. I'm kinda running out of time to do too much experimenting right now. | Before we declare victory we should probably discuss the issue of | handling lvalue/rvalue arguments to the function that's ultimately | called. sure. Can you explain the issue? br Thorsten

"Thorsten Ottosen" <nesotto@cs.auc.dk> writes:
"David Abrahams" <dave@boost-consulting.com> wrote in message news:uu0v5c248.fsf@boost-consulting.com... | "Thorsten Ottosen" <nesotto@cs.auc.dk> writes:
| > and to find an portable implementation of that (perhaps without a | > using declaration). | | Should be no trouble, I think. That said, I think you were on the | right track to a solution.
yeah maybe. I'm kinda running out of time to do too much experimenting right now.
| Before we declare victory we should probably discuss the issue of | handling lvalue/rvalue arguments to the function that's ultimately | called.
sure. Can you explain the issue?
The scheme forwards all overloads through a central function, rather than calling them directly. Naive forwarding schemes are prone to "erasing rvalueness", because function parameters are lvalues. You can also easily and mistakenly prevent rvalues from being passed by taking only T& parameters. We could try to force rvalues through a different overload of the outer function and use an identity function inside it to recreate rvalue-ness, but I think it's impossible in general and it doesn't seem to be worth it anyway. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

Thorsten Ottosen wrote:
namespace A { namespace detail { template< typename T > void f( const T& ) { std::cout << 1 << std::endl; }
template< typename T > void adl_f( const T& x ) { f( x ); } }
template< typename T > void f( const T& x ) { detail::adl_f( x ); }
// this is bad!! struct C {};
I assume you have control over namespace A, thus you can add: void f( const C& x ) { detail::f( x ); } and the problem is gone. Is this a feasible solution for you?
}
namespace B { class C {};
void f( const C& ) { std::cout << 2 << std::endl; } }
int main() { A::f( 42 );
A::C c0; A::f( c0 ); // error!
B::C c; A::f( c ); }
Regards, Daniel -- Daniel Frey aixigo AG - financial solutions & technology Schloß-Rahe-Straße 15, 52072 Aachen, Germany fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99 eMail: daniel.frey@aixigo.de, web: http://www.aixigo.de

| Thorsten Ottosen wrote: | > namespace A | > { | > template< typename T > | > void f( const T& x ) | > { | > detail::adl_f( x ); | > } | > | > // this is bad!! | > struct C {}; | | I assume you have control over namespace A, thus you can add: | | void f( const C& x ) | { | detail::f( x ); | } | | and the problem is gone. Is this a feasible solution for you? Not really since A would be namespace boost. I tried the stuff out with the range library, but it would affect all Ranges in boost, ie, tokenizer, sub_range, iterator_range and more. br Thorsten

Stefan Slapeta <stefan_nospam_@slapeta.com> writes:
Daniel James wrote:
[many things]
FYI, Thorsten checked in a test case (range/adl_conformance) to check ADL conformance on various compilers before he left for vacation.
It's not that this testcase tells us much about the range library, but the results are nevertheless interesting and show that some compilers still have their difficulties! Among these are the (current) Microsoft compiler(s), but also Intel: once again the tests pass on Windows and fail on Linux (one should mean they have different front ends)!
If there really is an intention to extend the use of ADL in the boost library, one perhaps should ask Microsoft to fix the issues in VC 8.
Has anyone reported the problem or even produced a simple test case? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams <dave@boost-consulting.com> wrote:
Stefan Slapeta <stefan_nospam_@slapeta.com> writes:
Has anyone reported the problem or even produced a simple test case?
I wrote a mail to Herb and there will be somebody looking at it. The test case is simple enough. Stefan

"Thorsten Ottosen" <nesotto@cs.auc.dk> writes:
Dear All,
I've put meself in a funny situation. I have a class with an begin() end() members, but I wan't to call boost::begin() boost::end() without the boost:: prefix so ADL is functional. Can that be done?
We ought to be seriously considering the approach of http://tinyurl.com/3tu8a for Boost functions that, like begin() and end(), rely on ADL. It may not solve the problem of accidental conformance, but at least it allows code that invokes these functions to be explicit about which algorithm is intended. If the boost function can develop some intelligence about detecting concept conformance of its parameters, it may allow us to avoid some accidental conformance too. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote in message news:uzn5ho9vf.fsf@boost-consulting.com... | "Thorsten Ottosen" <nesotto@cs.auc.dk> writes: | | > Dear All, | > | > I've put meself in a funny situation. I have a class with an begin() end() members, but I wan't to call boost::begin() boost::end() | > without the boost:: prefix so ADL is functional. Can that be done? | | We ought to be seriously considering the approach of | http://tinyurl.com/3tu8a for Boost functions that, like begin() and | end(), rely on ADL. If I understand this correctly, then it would mean we can use boost::end( r ) etc and still get ADL lookup ( Cool!! ) If so, is there any knowledge about how portable it works? | It may not solve the problem of accidental | conformance, but at least it allows code that invokes these functions | to be explicit about which algorithm is intended. If the boost | function can develop some intelligence about detecting concept | conformance of its parameters, it may allow us to avoid some | accidental conformance too. yes, concept checks would be ok, but won't happen until the next release. I would say this is a manor problem. br -Thorsten

"Thorsten Ottosen" <nesotto@cs.auc.dk> writes:
"David Abrahams" <dave@boost-consulting.com> wrote in message news:uzn5ho9vf.fsf@boost-consulting.com... | "Thorsten Ottosen" <nesotto@cs.auc.dk> writes: | | > Dear All, | > | > I've put meself in a funny situation. I have a class with an begin() end() members, but I wan't to call boost::begin() boost::end() | > without the boost:: prefix so ADL is functional. Can that be done? | | We ought to be seriously considering the approach of | http://tinyurl.com/3tu8a for Boost functions that, like begin() and | end(), rely on ADL.
If I understand this correctly, then it would mean we can use boost::end( r ) etc and still get ADL lookup ( Cool!! )
If so, is there any knowledge about how portable it works?
It's as portable as ADL is. It won't work where ADL doesn't work; otherwise it will work.
| It may not solve the problem of accidental | conformance, but at least it allows code that invokes these functions | to be explicit about which algorithm is intended. If the boost | function can develop some intelligence about detecting concept | conformance of its parameters, it may allow us to avoid some | accidental conformance too.
yes, concept checks would be ok, but won't happen until the next release. I would say this is a manor problem.
I didn't mean concept checks in the usual sense so much as SFINAE. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

-- David Abrahams" <dave@boost-consulting.com> wrote in message news:u7jsllb9r.fsf@boost-consulting.com... | "Thorsten Ottosen" <nesotto@cs.auc.dk> writes: | > yes, concept checks would be ok, but won't happen until the next | > release. I would say this is a manor problem. ^^^^^^^^^ I meant minor. | I didn't mean concept checks in the usual sense so much as SFINAE. you've lost me now. Were you looking for CT errors if the wrong type was passed? br Thorsten
participants (7)
-
Daniel Frey
-
Daniel James
-
David Abrahams
-
Eric Niebler
-
Stefan Slapeta
-
Stefan Slapeta
-
Thorsten Ottosen