Problem with boost::transform_iterator, std::pairs and templates.

Hi, I have a problem using the Boost.Iterators library correctly. The following minimal example does neither compile with GCC 4.2 nor with a current ICC 10.0 version. It seems that putting a boost::transform_iterator inside a pair makes it impossible to retrieve its value again using std::iterator_traits. I would welcome a proposal how to resolve the problem. I get the bug when using transform_iterator together with the MCSTL (Multi Core STL) and thus cannot change the internals. I would thus like to know if and how I can make the following work without touching the inner() and outer() functions themselves since I do not have the possibility to change the library code itself. Am I using boost::transform_iterator incorrectly? Kind Regards, Manuel == File Source == #include <iostream> #include <vector> #include <functional> #include <boost/iterator/transform_iterator.hpp> class plus_two : public std::unary_function<int, int> { public: int operator()(int x) const { return x + 2; } }; template <class Pair> void inner(Pair pair) { typedef typename Pair::first_type Iterator; typedef typename std::iterator_traits<Iterator>::value_type T; Pair p = pair; T *x = &p.first[0]; (void)x; } template<class InIterator> void outer(InIterator begin, InIterator end) { typedef typename std::iterator_traits<InIterator>::value_type ValueType; inner(std::make_pair(begin, end)); } int main(void) { int in[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; outer( // broken boost::make_transform_iterator(in, plus_two()), boost::make_transform_iterator(in + 10, plus_two())); outer(in, in+10); // working return 0; } == GCC 4.2.0 Output == user@host:~/tmp> gcc-4.2.0 --version gcc-4.2.0 (GCC) 4.2.0 Copyright (C) 2007 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. user@host:~/tmp> gcc-4.2.0 conflict.cpp conflict.cpp: In function 'void inner(Pair) [with Pair = std::pair<boost::transform_iterator<plus_two, int*, boost::use_default, boost::use_default>, boost::transform_iterator<plus_two, int*, boost::use_default, boost::use_default> >]': conflict.cpp:29: instantiated from 'void outer(InIterator, InIterator) [with InIterator = boost::transform_iterator<plus_two, int*, boost::use_default, boost::use_default>]' conflict.cpp:37: instantiated from here conflict.cpp:21: warning: taking address of temporary conflict.cpp:21: error: cannot convert 'boost::detail::operator_brackets_proxy<boost::transform_iterator<plus_t wo, int*, boost::use_default, boost::use_default> >*' to 'int*' in initialization == Intel C++ Compiler Output == user@host:~/tmp> icc -V Intel(R) C Compiler for applications running on Intel(R) 64, Version 10.0 Build 20070613 Package ID: l_cc_c_10.0.025 Copyright (C) 1985-2007 Intel Corporation. All rights reserved. FOR NON-COMMERCIAL USE ONLY user@host:~/tmp> icc conflict.cpp conflict.cpp(21): warning #1563: taking the address of a temporary T *x = &p.first[0]; ^ detected during: instantiation of "void inner(Pair) [with Pair=std::pair<boost::transform_iterator<plus_two, int *, boost::use_default, boost::use_default>, boost::transform_iterator<plus_two, int *, boost::use_default, boost::use_default>>]" at line 29 instantiation of "void outer(InIterator, InIterator) [with InIterator=boost::transform_iterator<plus_two, int *, boost::use_default, boost::use_default>]" at line 35 conflict.cpp(21): error: a value of type "boost::detail::operator_brackets_proxy<boost::transform_iterator<plus_t wo, int *, boost::use_default, boost::use_default>> *" cannot be used to initialize an entity of type "T={int} *" T *x = &p.first[0]; ^ detected during: instantiation of "void inner(Pair) [with Pair=std::pair<boost::transform_iterator<plus_two, int *, boost::use_default, boost::use_default>, boost::transform_iterator<plus_two, int *, boost::use_default, boost::use_default>>]" at line 29 instantiation of "void outer(InIterator, InIterator) [with InIterator=boost::transform_iterator<plus_two, int *, boost::use_default, boost::use_default>]" at line 35 compilation aborted for conflict.cpp (code 2)

on Thu Jul 19 2007, Manuel Holtgrewe <purestorm-AT-ggnore.net> wrote:
Hi,
I have a problem using the Boost.Iterators library correctly. The following minimal example does neither compile with GCC 4.2 nor with a current ICC 10.0 version.
It seems that putting a boost::transform_iterator inside a pair makes it impossible to retrieve its value again using std::iterator_traits.
That's not the conclusion I would draw from what you show below.
I would welcome a proposal how to resolve the problem. I get the bug when using transform_iterator together with the MCSTL (Multi Core STL) and thus cannot change the internals. I would thus like to know if and how I can make the following work without touching the inner() and outer() functions themselves since I do not have the possibility to change the library code itself.
Am I using boost::transform_iterator incorrectly?
I think so.
Kind Regards,
Manuel
== File Source ==
#include <iostream> #include <vector> #include <functional>
#include <boost/iterator/transform_iterator.hpp>
class plus_two : public std::unary_function<int, int> { public: int operator()(int x) const { return x + 2; } };
template <class Pair> void inner(Pair pair) { typedef typename Pair::first_type Iterator; typedef typename std::iterator_traits<Iterator>::value_type T;
Pair p = pair;
T *x = &p.first[0];
OK, first of all, if p.first is a transform_iterator, then the result of p.first[0] is not a reference as you might expect It's a temporary proxy object (see http://www.boost.org/libs/iterator/doc/iterator_facade.html#operator), which explains this warning and error:
conflict.cpp: In function 'void inner(Pair) [with Pair = std::pair<boost::transform_iterator<plus_two, int*, boost::use_default, boost::use_default>, boost::transform_iterator<plus_two, int*, boost::use_default, boost::use_default> >]': conflict.cpp:21: warning: taking address of temporary conflict.cpp:21: error: cannot convert 'boost::detail::operator_brackets_proxy<boost::transform_iterator<plus_t wo, int*, boost::use_default, boost::use_default> >*' to 'int*' in initialization
Secondly, even if it could be a reference, (or you used the otherwise-equivalent &*p.first) your transform function returns by value, not by reference. So that too would be a reference to a temporary. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com The Astoria Seminar ==> http://www.astoriaseminar.com
participants (2)
-
David Abrahams
-
Manuel Holtgrewe