Opened 10 years ago

Closed 9 years ago

#7376 closed Bugs (fixed)

join_iterator.hpp compiler warning

Reported by: Leonid Gershanovich <gleonid@…> Owned by: Neil Groves
Milestone: To Be Determined Component: range
Version: Boost 1.51.0 Severity: Problem
Keywords: Cc:

Description

getting compiler warning in boost/range/detail/join_iterator.hpp:74

53 template<typename Iterator1
54        , typename Iterator2
55        , typename Reference
56 >
57 class join_iterator_union
58 {
59 public:
60     typedef Iterator1 iterator1_t;
61     typedef Iterator2 iterator2_t;
62
63     join_iterator_union() {}
64     join_iterator_union(unsigned int /*selected*/, const iterator1_t& it1, const iterator2_t& it2) : m_it1(it1), m_it2(it2) {}
65
66     iterator1_t& it1() { return m_it1; }
67     const iterator1_t& it1() const { return m_it1; }
68
69     iterator2_t& it2() { return m_it2; }
70     const iterator2_t& it2() const { return m_it2; }
71
72     Reference dereference(unsigned int selected) const
73     {
74         return selected ? *m_it2 : *m_it1;
75     }
76
77     bool equal(const join_iterator_union& other, unsigned int selected) const
78     {
79         return selected
80             ? m_it2 == other.m_it2
81             : m_it1 == other.m_it1;
82     }
83
84 private:
85     iterator1_t m_it1;
86     iterator2_t m_it2;
87 };

I am using it in a way when iterator1_t and iterator1_t are different types. Furthermore, underlying types (*m_it1 and *m_it2) are different, but both are convertible to Reference, but not to each other.

In other words expression *m_it2 cannot be converted to type iterated by iterator1_t ( *m_it1 ). But can be safely converted to type Reference

please consider following patch:

@@ -68,7 +68,9 @@
 
     Reference dereference(unsigned int selected) const
     {
-        return selected ? *m_it2 : *m_it1;
+        if (selected)
+           return *m_it2;
+        return *m_it1;
     }
 
     bool equal(const join_iterator_union& other, unsigned int selected) const

Change History (7)

comment:1 by viboes, 10 years ago

Component: Nonerange
Owner: set to Neil Groves

comment:2 by Nathan Ridge, 9 years ago

Could you please give an example of Iterator1 and Iterator2 types for which this problem arises?

comment:3 by anonymous, 9 years ago

here is a sample code that produces compiler error:

#include "boost/range/join.hpp"

struct A {};
struct B: public A {} ;
struct C: public A {};

int main()
{
  B b[10];
  C c[10];
  typedef ::boost::range_detail::join_iterator< const C*, const B* , const A&, const A& > join_iterator;
  join_iterator it(::boost::make_iterator_range(c), 
                   ::boost::make_iterator_range(b),
                   ::boost::range_detail::join_iterator_begin_tag());
  *it;
}

error:

boost/range/detail/join_iterator.hpp:74: error: no match for ternary 'operator?:' in '(selected != 0u) ? *(const B*)((const boost::range_detail::join_iterator_union<const C*, const B*, const A&>*)this)->boost::range_detail::join_iterator_union<const C*, const B*, const A&>::m_it2 : *(const C*)((const boost::range_detail::join_iterator_union<const C*, const B*, const A&>*)this)->boost::range_detail::join_iterator_union<const C*, const B*, const A&>::m_it1

with patch suggested earlier this sample compiles without errors.

in reply to:  3 comment:4 by Nathan Ridge, 9 years ago

Replying to anonymous:

here is a sample code that produces compiler error:

#include "boost/range/join.hpp"

struct A {};
struct B: public A {} ;
struct C: public A {};

int main()
{
  B b[10];
  C c[10];
  typedef ::boost::range_detail::join_iterator< const C*, const B* , const A&, const A& > join_iterator;
  join_iterator it(::boost::make_iterator_range(c), 
                   ::boost::make_iterator_range(b),
                   ::boost::range_detail::join_iterator_begin_tag());
  *it;
}

error:

boost/range/detail/join_iterator.hpp:74: error: no match for ternary 'operator?:' in '(selected != 0u) ? *(const B*)((const boost::range_detail::join_iterator_union<const C*, const B*, const A&>*)this)->boost::range_detail::join_iterator_union<const C*, const B*, const A&>::m_it2 : *(const C*)((const boost::range_detail::join_iterator_union<const C*, const B*, const A&>*)this)->boost::range_detail::join_iterator_union<const C*, const B*, const A&>::m_it1

with patch suggested earlier this sample compiles without errors.

join_iterator is not part of the public interface of Boost.Range, it's just an implementation detail of boost::range::join().

boost::range::join() currently requires that the value type of the second range be convertible to the value type of the first range. Perhaps this requirement could be relaxed, to allow cases where the two value types are convertible to a common type but not to each other, but then we need to either:

  1. get join_iterator to figure out what that common type is (which is possible in some cases like this one, but not in the general case); or
  2. provide a public interface for the user to specify this common type (right now you are specifying it by instantiating join_iterator with a custom Reference template parameter, which is not public interface)

(or both).

Your patch will probably be part of either solution, but I am inclined to wait until we have a complete solution before applying it.

comment:5 by Neil Groves, 9 years ago

Status: newassigned

I think that specifying the Reference type of the join_iterator is already a way to manage the "common type" problem. I don't think that there is a general solution to the "common type" problem when we consider the potential interaction with user-defined types. It is possible that the desired return type isn't a reference in any of the input types. Manual specification is already possible, is simple and works.

I'm going to apply the small change as requested.

comment:6 by Neil Groves, 9 years ago

Additionally aschoedl provided some extra code to do better automatic deduction of common-types.

comment:7 by Neil Groves, 9 years ago

Resolution: fixed
Status: assignedclosed
Note: See TracTickets for help on using tickets.