[iterator] unrelated type problem with iterator_facade arrow operator
Can someone confirm if the attached code doesn't compile intentionally or if this is a bug? I'm sorry for not posting a minimal example but I couldn't figure out how to reduce the problem. It requires Windows (uses ATL::CAdapt and ATL::CComBSTR) and I've tested using VS 2005 and VS2008. This bug manifests when the Reference type has overloaded the address-of operator to return a type not implicitly convertible to Value * (I believe). Changing lines 324-326 in iterator_facade.hpp from: static type make(Reference x) { return implicit_cast<type>(&x); } to: static type make(Reference x) { return implicit_cast<type>(boost::addressof(x)); } and adding the appropriate include makes the attached code compile. Full error log below: 1>c:\dev\vendor\boost\1.37.0\boost\iterator\iterator_facade.hpp(326) : error C2664: 'boost::implicit_cast' : cannot convert parameter 1 from 'BSTR *' to 'ATL::CComBSTR *' 1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast 1> c:\dev\vendor\boost\1.37.0\boost\iterator\iterator_facade.hpp(325) : while compiling class template member function 'ATL::CComBSTR *boost::detail::operator_arrow_result<ValueType,Reference,Pointer>::make(Reference)' 1> with 1> [ 1> ValueType=ATL::CComBSTR, 1> Reference=ATL::CComBSTR &, 1> Pointer=ATL::CComBSTR * 1> ] 1> c:\dev\vendor\boost\1.37.0\boost\iterator\iterator_facade.hpp(641) : see reference to class template instantiation 'boost::detail::operator_arrow_result<ValueType,Reference,Pointer>' being compiled 1> with 1> [ 1> ValueType=ATL::CComBSTR, 1> Reference=ATL::CComBSTR &, 1> Pointer=ATL::CComBSTR * 1> ] 1> c:\dev\vendor\boost\1.37.0\boost\iterator\iterator_adaptor.hpp(271) : see reference to class template instantiation 'boost::iterator_facade<Derived,Value,CategoryOrTraversal,Reference,Difference>' being compiled 1> with 1> [ 1> Derived=test::atl::CAdapt_iterator<std::_Vector_iterator<ATL::CAdapt<ATL::CComBSTR>,std::allocator<ATL::CAdapt<ATL::CComBSTR>>>>, 1> Value=ATL::CComBSTR, 1> CategoryOrTraversal=std::random_access_iterator_tag, 1> Reference=ATL::CComBSTR &, 1> Difference=__w64 int 1> ] 1> c:\dev\personal\boost\iterator_adaptor_bug\main.cpp(65) : see reference to class template instantiation 'boost::iterator_adaptor<Derived,Base,Value,Traversal,Reference>' being compiled 1> with 1> [ 1> Derived=test::atl::CAdapt_iterator<std::_Vector_iterator<ATL::CAdapt<ATL::CComBSTR>,std::allocator<ATL::CAdapt<ATL::CComBSTR>>>>, 1> Base=std::_Vector_iterator<ATL::CAdapt<ATL::CComBSTR>,std::allocator<ATL::CAdapt<ATL::CComBSTR>>>, 1> Value=ATL::CComBSTR, 1> Traversal=std::random_access_iterator_tag, 1> Reference=ATL::CComBSTR & 1> ] 1> c:\dev\personal\boost\iterator_adaptor_bug\main.cpp(103) : see reference to class template instantiation 'test::atl::CAdapt_iterator<Iterator>' being compiled 1> with 1> [ 1> Iterator=std::_Vector_iterator<ATL::CAdapt<ATL::CComBSTR>,std::allocator<ATL::CAdapt<ATL::CComBSTR>>> 1> ] Thanks for any insight, --Michael Fawcett
Michael Fawcett <michael.fawcett <at> gmail.com> writes:
Can someone confirm if the attached code doesn't compile intentionally or if this is a bug? I'm sorry for not posting a minimal example but I couldn't figure out how to reduce the problem.
Ping with complete code this time. Hopefully that will help with a response. I also added my work-around to the code. #include <boost/iterator/iterator_adaptor.hpp> #include <boost/iterator/iterator_traits.hpp> #include <boost/type_traits/add_const.hpp> #include <boost/type_traits/is_convertible.hpp> #include <boost/utility/addressof.hpp> #include <boost/utility/enable_if.hpp> #include <atlbase.h> #include <cassert> #include <vector> //#define POSSIBLE_FIX #ifdef POSSIBLE_FIX // Not sure if this is a bug in Boost (doubt it) or just necessary // since CComBSTR overloads the address-of operator to return a // type (BSTR) that is not implicitly convertible to CComBSTR *. namespace boost { namespace detail { template <typename Reference, typename Pointer> struct operator_arrow_result<ATL::CComBSTR, Reference, Pointer> { typedef typename mpl::if_< is_reference<Reference> , Pointer , operator_arrow_proxy<ATL::CComBSTR> >::type type; static type make(Reference x) { return implicit_cast<type>(boost::addressof(x)); } }; } } #endif namespace detail { template <typename T> struct CAdapt_pointee { }; template <typename T> struct CAdapt_pointee<ATL::CAdapt<T> > { typedef T type; }; template <typename Iterator, typename T> struct m_T_type_add_const_conditionally { typedef typename CAdapt_pointee<typename boost::iterator_value<Iterator>::type>::type type; }; template <typename Iterator, typename T> struct m_T_type_add_const_conditionally<Iterator, const T *> { typedef typename boost::add_const<typename CAdapt_pointee<typename boost::iterator_value<Iterator>::type>::type>::type type; }; template <typename T> struct m_T_type { typedef typename m_T_type_add_const_conditionally<T, typename boost::iterator_pointer<T>::type>::type type; }; } template <class Iterator> class CAdapt_iterator : public boost::iterator_adaptor < CAdapt_iterator<Iterator>, Iterator, typename detail::m_T_type<Iterator>::type, typename boost::iterator_category<Iterator>::type, typename detail::m_T_type<Iterator>::type & > { private: struct enabler { }; typedef typename detail::m_T_type<Iterator>::type &reference_type; public: CAdapt_iterator() { } CAdapt_iterator(Iterator p) : CAdapt_iterator::iterator_adaptor_(p) { } template <class OtherValue> CAdapt_iterator(const CAdapt_iterator<OtherValue> &other, typename boost::enable_if<boost::is_convertible<OtherValue *, Iterator *>, enabler>::type = enabler()) : CAdapt_iterator::iterator_adaptor_(other.base()) { } private: friend class boost::iterator_core_access; reference_type dereference() const { return this->base()->m_T; } }; template <typename Iterator> CAdapt_iterator<Iterator> make_CAdapt_iterator(Iterator i) { return CAdapt_iterator<Iterator>(i); } int main() { std::vector<CAdapt<CComBSTR> > buffer(1, CComBSTR(L"Hello, World!")); assert(*make_CAdapt_iterator(buffer.begin()) == L"Hello, World!"); // This line causes the compile-error if POSSIBLE_FIX is not defined make_CAdapt_iterator(buffer.begin())->Empty(); assert(buffer[0].m_T.Length() == 0); } --Michael Fawcett
participants (1)
-
Michael Fawcett