iterator_facade triggers ADL, fails to compile

Hello, the attached file arg_names.cpp fails to compile (VS2008) when using boost::lambda::_1 or boost::phoenix::arg_names::_1. The compilation succeeds when using boost::bind. All three variations are in the attached code for illustration. The compilation fails due to the presence of a templated operator& definition which is introduced by the instantiation of a class that is declared "andable" (from boost/operators.hpp). The compilation fails because iterator_facade triggers ADL in BOOST_ITERATOR_FACADE_INTEROP and finds the aforementioned operator& when comparing iterators that carry boost::lambda::_1 or boost::phoenix::arg_names::_1 as part of their type specification. In the example, this is illustrated by using filter_iterator. It is not clear to me what exactly the mechanism is that causes this ADL problem. But the static_cast in BOOST_ITERATOR_FACADE_INTEROP can be implemented using references instead of pointers, as shown below, which makes the problem disappear. In any case, using operator& on the iterator may be problematic if the iterator overloads operator&. --- C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/boost_1_46_1/boost/iterator/iterator_facade.hpp Wed May 25 11:42:14 2011 +++ C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/boost_1_46_1/boost/iterator/iterator_facade - Copy.hpp Wed May 25 11:41:49 2011 @@ -819,8 +819,8 @@ is_interoperable< Derived1, Derived2 >::value \ )); \ return_prefix iterator_core_access::base_op( \ - *static_cast<Derived1 const*>(&lhs) \ - , *static_cast<Derived2 const*>(&rhs) \ + static_cast<Derived1 const&>(lhs) \ + , static_cast<Derived2 const&>(rhs) \ , BOOST_ITERATOR_CONVERTIBLE(Derived2,Derived1) \ ); \ } Does anyone understand better what is happening? Or can we simply adopt the change? Regards, Arno -- Dr. Arno Schödl | aschoedl@think-cell.com Technical Director think-cell Software GmbH | Chausseestr. 8/E | 10115 Berlin | Germany http://www.think-cell.com | phone +49 30 666473-10 | US phone +1 800 891 8091 Amtsgericht Berlin-Charlottenburg, HRB 85229 | European Union VAT Id DE813474306 Directors: Dr. Markus Hannebauer, Dr. Arno Schoedl

On 25/05/2011 11:58, Arno Schödl wrote:
Hello,
the attached file arg_names.cpp fails to compile (VS2008) when using boost::lambda::_1 or boost::phoenix::arg_names::_1. The compilation succeeds when using boost::bind. All three variations are in the attached code for illustration.
The compilation fails due to the presence of a templated operator& definition which is introduced by the instantiation of a class that is declared "andable" (from boost/operators.hpp).
The compilation fails because iterator_facade triggers ADL in BOOST_ITERATOR_FACADE_INTEROP and finds the aforementioned operator& when comparing iterators that carry boost::lambda::_1 or boost::phoenix::arg_names::_1 as part of their type specification. In the example, this is illustrated by using filter_iterator.
It is not clear to me what exactly the mechanism is that causes this ADL problem. But the static_cast in BOOST_ITERATOR_FACADE_INTEROP can be implemented using references instead of pointers, as shown below, which makes the problem disappear. In any case, using operator& on the iterator may be problematic if the iterator overloads operator&.
--- C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/boost_1_46_1/boost/iterator/iterator_facade.hpp Wed May 25 11:42:14 2011 +++ C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/boost_1_46_1/boost/iterator/iterator_facade - Copy.hpp Wed May 25 11:41:49 2011 @@ -819,8 +819,8 @@ is_interoperable< Derived1, Derived2>::value \ )); \ return_prefix iterator_core_access::base_op( \ - *static_cast<Derived1 const*>(&lhs) \ - , *static_cast<Derived2 const*>(&rhs) \ + static_cast<Derived1 const&>(lhs) \ + , static_cast<Derived2 const&>(rhs) \ , BOOST_ITERATOR_CONVERTIBLE(Derived2,Derived1) \ ); \ }
An alternative could also have been to use boost::addressof

--- C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/boost_1_46_1/boost/iterator/iterator_facade.hpp Wed May 25 11:42:14 2011 +++ C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/boost_1_46_1/boost/iterator/iterator_facade - Copy.hpp Wed May 25 11:41:49 2011 @@ -819,8 +819,8 @@ is_interoperable< Derived1, Derived2>::value \ )); \ return_prefix iterator_core_access::base_op( \ - *static_cast<Derived1 const*>(&lhs) \ - , *static_cast<Derived2 const*>(&rhs) \ + static_cast<Derived1 const&>(lhs) \ + , static_cast<Derived2 const&>(rhs) \ , BOOST_ITERATOR_CONVERTIBLE(Derived2,Derived1) \ ); \ }
An alternative could also have been to use boost::addressof
I was aware of that, but creating the dependency on addressof seems unnecessary if a simple reference cast does the job. Is there any particular reason why the cast is implemented through pointers? Searching through boost for *static_cast, there are a few more places where a static_cast< [const] & > would do but the route through pointers has been taken. Any reason not to replace them wholesale to avoid problems with overloaded operator& and in general to make the code more concise? boost_1_46_1\boost\accumulators\framework\depends_on.hpp(276): : Accumulator(*static_cast<Accumulator const *>(&that)) boost_1_46_1\boost\accumulators\framework\accumulators\droppable_accumulator.hpp(183): : Accumulator(*static_cast<Accumulator const *>(&that)) boost_1_46_1\boost\algorithm\string\classification.hpp(246): *static_cast<const Pred1T*>(&Pred1), boost_1_46_1\boost\algorithm\string\classification.hpp(247): *static_cast<const Pred2T*>(&Pred2) ); boost_1_46_1\boost\algorithm\string\classification.hpp(270): *static_cast<const Pred1T*>(&Pred1), boost_1_46_1\boost\algorithm\string\classification.hpp(271): *static_cast<const Pred2T*>(&Pred2)); boost_1_46_1\boost\algorithm\string\classification.hpp(289): return detail::pred_notF<PredT>(*static_cast<const PredT*>(&Pred)); boost_1_46_1\boost\iterator\iterator_facade.hpp(570): return *static_cast<I*>(&facade); boost_1_46_1\boost\iterator\iterator_facade.hpp(576): return *static_cast<I const*>(&facade); boost_1_46_1\boost\iterator\iterator_facade.hpp(732): tmp(*static_cast<I*>(&i)); boost_1_46_1\boost\iterator\iterator_facade.hpp(822): *static_cast<Derived1 const*>(&lhs) \ //// our problem boost_1_46_1\boost\iterator\iterator_facade.hpp(823): , *static_cast<Derived2 const*>(&rhs) \ //// our problem boost_1_46_1\boost\xpressive\detail\static\static.hpp(104): return *static_cast<stacked_xpression<Top, Next> const *>(&next); Arno -- Dr. Arno Schödl | aschoedl@think-cell.com Technical Director think-cell Software GmbH | Chausseestr. 8/E | 10115 Berlin | Germany http://www.think-cell.com | phone +49 30 666473-10 | US phone +1 800 891 8091 Amtsgericht Berlin-Charlottenburg, HRB 85229 | European Union VAT Id DE813474306 Directors: Dr. Markus Hannebauer, Dr. Arno Schoedl

On Wed, May 25, 2011 at 5:22 AM, Arno Schödl <aschoedl@think-cell.com>wrote:
--- C:/Program Files (x86)/Microsoft Visual Studio
9.0/VC/boost_1_46_1/boost/iterator/iterator_facade.hpp Wed May 25 11:42:14 2011
+++ C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/boost_1_46_1/boost/iterator/iterator_facade - Copy.hpp Wed May 25 11:41:49 2011 @@ -819,8 +819,8 @@ is_interoperable< Derived1, Derived2>::value \ )); \ return_prefix iterator_core_access::base_op( \ - *static_cast<Derived1 const*>(&lhs) \ - , *static_cast<Derived2 const*>(&rhs) \ + static_cast<Derived1 const&>(lhs) \ + , static_cast<Derived2 const&>(rhs) \ , BOOST_ITERATOR_CONVERTIBLE(Derived2,Derived1) \ ); \ }
An alternative could also have been to use boost::addressof
I was aware of that, but creating the dependency on addressof seems unnecessary if a simple reference cast does the job. Is there any particular reason why the cast is implemented through pointers?
Searching through boost for *static_cast, there are a few more places where a static_cast< [const] & > would do but the route through pointers has been taken. Any reason not to replace them wholesale to avoid problems with overloaded operator& and in general to make the code more concise?
I believe casting through pointers is more restrictive and predictable than casting through references (e.g., T& could be even implicitly convertible to U& without T* convertible to U*; even the case of converting base_type& to derived_type& could be using some converting constructor in derived_type), so I don't think this would be a wise change indiscriminately. It looks to me like in this iterator_facade case, though, a reference cast is probably fine... [...snip instances of "*static_cast<" in boost...] - Jeff

I believe casting through pointers is more restrictive and predictable than casting through references (e.g., T& could be even implicitly convertible to U& without T* convertible to U*; even the case of converting base_type& to derived_type& could be using some converting constructor in derived_type), so I don't think this would be a wise change indiscriminately.
It looks to me like in this iterator_facade case, though, a reference cast is probably fine...
Of course, I missed that. Arguably, in all such cases, boost::addressof should be used because the result of an overloaded operator& is just as unpredictable as the result of a conversion operator. So something like: template< class T, class S > T const& inheritance_cast( S const& s ) { return *static_cast< T const* >( boost::addressof(s) ); } template< class T, class S > T & inheritance_cast( S & s ) { return *static_cast< T * >( boost::addressof(s) ); } Arno -- Dr. Arno Schödl | aschoedl@think-cell.com Technical Director think-cell Software GmbH | Chausseestr. 8/E | 10115 Berlin | Germany http://www.think-cell.com | phone +49 30 666473-10 | US phone +1 800 891 8091 Amtsgericht Berlin-Charlottenburg, HRB 85229 | European Union VAT Id DE813474306 Directors: Dr. Markus Hannebauer, Dr. Arno Schoedl
participants (3)
-
Arno Schödl
-
Jeffrey Lee Hellrung, Jr.
-
Mathias Gaunard