Adapters library: using back_insertor with make_transform_iterator

How does this work? I'm trying to use the make_transform_iterator to make a writeable output iterator (looks like it is referred to as a "Writeable LValue" in the iterator template code), but I can't figure out how to do it. Here's the example: (I know that I could have used the make_transform_iterators on the source iterators in this toy example, but that won't do for my real application) typedef map<int,string> Map; typedef vector<int> V1; typedef vector<string> V2; string convert(int iValue) { return str(ostringstream() << iValue); } int _tmain(int argc, _TCHAR* argv[]) { V1 aSourceVector; V2 aTargetVector; copy(aSourceVector.begin(), aSourceVector.end(), make_transform_iterator(back_inserter(aTargetVector), boost::bind(convert, _1)); } The compiler (MSVC 7.1.3008) generates a compile errors like at the end of this message. Anybody know the right way to do this? Can you use an iterator adaptor as an output iterator, or is this wishful thinking on my part? Rob. Compiling... make_transform_iterator.cpp d:\scratch\make_transform_iterator\make_transform_iterator.cpp(20) : error C2514: 'std::basic_ostringstream<_Elem,_Traits,_Alloc>' : class has no constructors with [ _Elem=char, _Traits=std::char_traits<char>, _Alloc=std::allocator<char> ] d:\scratch\make_transform_iterator\make_transform_iterator.cpp(20) : see reference to class template instantiation 'std::basic_ostringstream<_Elem,_Traits,_Alloc>' being compiled with [ _Elem=char, _Traits=std::char_traits<char>, _Alloc=std::allocator<char> ] d:\scratch\make_transform_iterator\make_transform_iterator.cpp(20) : error C3861: 'str': identifier not found, even with argument-dependent lookup d:\svn\code\thirdpty\boost\boost_1.32.0\boost\iterator\iterator_facade.hpp(6 52) : error C2182: 'n' : illegal use of type 'void' d:\svn\code\thirdpty\boost\boost_1.32.0\boost\iterator\iterator_adaptor.hpp( 266) : see reference to class template instantiation 'boost::iterator_facade<Derived,Value,CategoryOrTraversal,Reference,Differen ce>' being compiled with [ Derived=boost::transform_iterator<boost::_bi::bind_t<std::string,std::string (__cdecl *)(int),boost::_bi::list1<boost::_bi::list_av_1<boost::arg<1>>::B1>>,std::ba ck_insert_iterator<V2>,boost::use_default,boost::use_default>, Value=boost::mpl::identity<boost::detail::transform_iterator_base<boost::_bi ::bind_t<std::string,std::string (__cdecl *)(int),boost::_bi::list1<boost::_bi::list_av_1<boost::arg<1>>::B1>>,std::ba ck_insert_iterator<V2>,boost::use_default,boost::use_default>::cv_value_type
::type,
CategoryOrTraversal=boost::mpl::identity<boost::incrementable_traversal_tag> ::type, Reference=boost::mpl::identity<boost::detail::transform_iterator_base<boost: :_bi::bind_t<std::string,std::string (__cdecl *)(int),boost::_bi::list1<boost::_bi::list_av_1<boost::arg<1>>::B1>>,std::ba ck_insert_iterator<V2>,boost::use_default,boost::use_default>::cv_value_type
::type,
Difference=boost::iterator_difference<std::back_insert_iterator<V2>>::type ] d:\svn\code\thirdpty\boost\boost_1.32.0\boost\iterator\transform_iterator.hp p(92) : see reference to class template instantiation 'boost::iterator_adaptor<Derived,Base,Value,Traversal,Reference>' being compiled with [ Derived=boost::transform_iterator<boost::_bi::bind_t<std::string,std::string (__cdecl *)(int),boost::_bi::list1<boost::_bi::list_av_1<boost::arg<1>>::B1>>,std::ba ck_insert_iterator<V2>,boost::use_default,boost::use_default>, Base=std::back_insert_iterator<V2>, Value=boost::detail::transform_iterator_base<boost::_bi::bind_t<std::string, std::string (__cdecl *)(int),boost::_bi::list1<boost::_bi::list_av_1<boost::arg<1>>::B1>>,std::ba ck_insert_iterator<V2>,boost::use_default,boost::use_default>::cv_value_type , Traversal=boost::use_default, Reference=boost::detail::transform_iterator_base<boost::_bi::bind_t<std::str ing,std::string (__cdecl *)(int),boost::_bi::list1<boost::_bi::list_av_1<boost::arg<1>>::B1>>,std::ba ck_insert_iterator<V2>,boost::use_default,boost::use_default>::reference ] d:\scratch\make_transform_iterator\make_transform_iterator.cpp(28) : see reference to class template instantiation 'boost::transform_iterator<UnaryFunction,Iterator,Reference,Value>' being compiled with [ UnaryFunction=boost::_bi::bind_t<std::string,std::string (__cdecl *)(int),boost::_bi::list1<boost::_bi::list_av_1<boost::arg<1>>::B1>>, Iterator=std::back_insert_iterator<V2>, Reference=boost::use_default, Value=boost::use_default ] d:\svn\code\thirdpty\boost\boost_1.32.0\boost\iterator\iterator_facade.hpp(6 92) : error C2182: 'n' : illegal use of type 'void' d:\svn\code\thirdpty\boost\boost_1.32.0\boost\iterator\iterator_facade.hpp(6 98) : error C2182: 'n' : illegal use of type 'void' d:\svn\code\thirdpty\boost\boost_1.32.0\boost\iterator\iterator_facade.hpp(7 04) : error C2182: 'x' : illegal use of type 'void' d:\svn\code\thirdpty\boost\boost_1.32.0\boost\iterator\iterator_adaptor.hpp( 326) : error C2182: 'n' : illegal use of type 'void' d:\scratch\make_transform_iterator\make_transform_iterator.cpp(28) : error C2143: syntax error : missing ')' before ';' Build log was saved at "file://d:\scratch\make_transform_iterator\Debug\BuildLog.htm" make_transform_iterator - 8 error(s), 0 warning(s)

"Robert Mathews" <rmathews@envoyww.com> writes:
How does this work?
I'm trying to use the make_transform_iterator to make a writeable output iterator (looks like it is referred to as a "Writeable LValue" in the iterator template code
Don't look at the code; read the documentation. The meaning of "writeable lvalue iterator" is detailed in the paper here: http://www.boost.org/libs/iterator/doc/index.html#new-style-iterators
), but I can't figure out how to do it.
Here's the example: (I know that I could have used the make_transform_iterators on the source iterators in this toy example, but that won't do for my real application)
typedef map<int,string> Map; typedef vector<int> V1; typedef vector<string> V2; string convert(int iValue) { return str(ostringstream() << iValue); }
int _tmain(int argc, _TCHAR* argv[]) { V1 aSourceVector; V2 aTargetVector; copy(aSourceVector.begin(), aSourceVector.end(), make_transform_iterator(back_inserter(aTargetVector), boost::bind(convert, _1)); }
Okay, let's review what a transform_iterator does, from http://www.boost.org/libs/iterator/doc/transform_iterator.html: The transform iterator adapts an iterator by modifying the operator* to apply a function object to the result of dereferencing the iterator and returning the result. So your transform_iterator's operator* is going to apply convert to the result of dereferencing a back_insert_iterator. Okay, that's your first problem. Do you know what you get when you dereference a back_insert_iterator? According to my copy of the standard, back_insert_iterator's operator* has the following signature: back_insert_iterator<Container>& operator*(); In other words, it returns a reference to a back_insert_iterator. Since convert takes an int, you have an impedance mismatch. Sounds like you want something more like function_output_iterator: http://www.boost.org/libs/iterator/doc/function_output_iterator.html It doesn't adapt an iterator, and I'm guessing you don't really want to adapt an iterator anyway (you could just use push_back, or more likely in your case, operator<<), but if I'm wrong, you can always embed the iterator in the function object you adapt. HTH, -- Dave Abrahams Boost Consulting www.boost-consulting.com

Yes, that's what I needed, thank you very much. FWIW, I couldn't find make_function_output_iterator when I first looked at the documentation, and then I ended out trying to read the code in the iterators library instead ... which was about when I gave up and posted. I rewrote it as follows, binding to the convert function and then sending that result to the push_back, and it now looks like the following. Unfortunately, vector::push_back is overloaded, so that the cast is really ugly. But it works. int _tmain(int argc, _TCHAR* argv[]) { V1 aSourceVector; V2 aTargetVector; aSourceVector.push_back(43); copy(aSourceVector.begin(), aSourceVector.end(), make_function_output_iterator( boost::bind((void (vector<string>::*)(const string&))&vector<string>::push_back, boost::ref(aTargetVector), boost::bind(convert,_1)))); } "David Abrahams" <dave@boost-consulting.com> wrote in message news:u4qbfc7k9.fsf@boost-consulting.com...
"Robert Mathews" <rmathews@envoyww.com> writes:
How does this work?
I'm trying to use the make_transform_iterator to make a writeable output iterator (looks like it is referred to as a "Writeable LValue" in the iterator template code
Don't look at the code; read the documentation. The meaning of "writeable lvalue iterator" is detailed in the paper here: http://www.boost.org/libs/iterator/doc/index.html#new-style-iterators
), but I can't figure out how to do it.
Here's the example: (I know that I could have used the make_transform_iterators on the source iterators in this toy example, but that won't do for my real application)
typedef map<int,string> Map; typedef vector<int> V1; typedef vector<string> V2; string convert(int iValue) { return str(ostringstream() << iValue); }
int _tmain(int argc, _TCHAR* argv[]) { V1 aSourceVector; V2 aTargetVector; copy(aSourceVector.begin(), aSourceVector.end(), make_transform_iterator(back_inserter(aTargetVector), boost::bind(convert, _1)); }
Okay, let's review what a transform_iterator does, from http://www.boost.org/libs/iterator/doc/transform_iterator.html:
The transform iterator adapts an iterator by modifying the operator* to apply a function object to the result of dereferencing the iterator and returning the result.
So your transform_iterator's operator* is going to apply convert to the result of dereferencing a back_insert_iterator. Okay, that's your first problem. Do you know what you get when you dereference a back_insert_iterator?
According to my copy of the standard, back_insert_iterator's operator* has the following signature:
back_insert_iterator<Container>& operator*();
In other words, it returns a reference to a back_insert_iterator. Since convert takes an int, you have an impedance mismatch.
Sounds like you want something more like function_output_iterator: http://www.boost.org/libs/iterator/doc/function_output_iterator.html
It doesn't adapt an iterator, and I'm guessing you don't really want to adapt an iterator anyway (you could just use push_back, or more likely in your case, operator<<), but if I'm wrong, you can always embed the iterator in the function object you adapt.
HTH,
-- Dave Abrahams Boost Consulting www.boost-consulting.com
participants (2)
-
David Abrahams
-
Robert Mathews