MPL - mpl::sequence to std::sequence

Hi, what is the easiest way to convert an mpl::sequence to an std::sequence? I'm using such conversions a lot when unit-testing meta-code. I just wrote two versions of algorithms, a compile-time and the runtime one, and then compare their outputs. I recall hearing something about mpl::for_each having defined an operator () for runtime purposes, but the details don't seem to be documented anywhere. I came up with the attached code, of which the "to_compile_time" might actually be of general interest. It's a function that converts a runtime integer to a compile time integer. Code-generation-wise it's a horror and it could be more generic, but it gets the job done for me. I'd like to hear if there are more elegant solutions for this though, as it seems like too much code. Thanks, Jaap Suter

From: "Jaap Suter" <boost@jaapsuter.com>
what is the easiest way to convert an mpl::sequence to an std::sequence?
I'm using such conversions a lot when unit-testing meta-code. I just wrote two versions of algorithms, a compile-time and the runtime one, and then compare their outputs.
I recall hearing something about mpl::for_each having defined an operator () for runtime purposes, but the details don't seem to be documented anywhere.
Yeah, I guess Aleksey and Dave have been busy with the forthcoming MPL book, but as I understand from list postings, the MPL docs will be updated in Boost 1.32, and mpl::for_each is one of the more useful components. Since it's not documented, I learned how it works from Aleksey. The following works with your code: template<class T> struct to_sequence { public: to_sequence(T &s) : sequence(s) {} template<class Element> void operator()(Element e) { sequence.push_back(e.value); } private: T &sequence; }; ... // int_vector r_list = to_runtime<c_list>(); int_vector r_list; boost::mpl::for_each<c_list>(to_sequence<int_vector>(r_list)); Regards, Terje

Terje Slettebø <tslettebo@broadpark.no> writes:
template<class T> struct to_sequence { public: to_sequence(T &s) : sequence(s) {}
template<class Element> void operator()(Element e) { sequence.push_back(e.value); }
private: T &sequence; };
...
// int_vector r_list = to_runtime<c_list>();
int_vector r_list;
boost::mpl::for_each<c_list>(to_sequence<int_vector>(r_list));
Better yet: int_vector r_list; boost::mpl::for_each<c_list>(std::back_inserter(r_list)); Enjoy ;-) -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
Terje Slettebø <tslettebo@broadpark.no> writes:
// int_vector r_list = to_runtime<c_list>();
int_vector r_list;
boost::mpl::for_each<c_list>(to_sequence<int_vector>(r_list));
Better yet:
int_vector r_list; boost::mpl::for_each<c_list>(std::back_inserter(r_list));
Enjoy ;-)
Um, how does this work? back_inserter returns an iterator, not a function object; is there some magic in mpl::for_each that I can't see? Maybe I'm looking at the wrong version?

"Peter Dimov" <pdimov@mmltd.net> writes:
David Abrahams wrote:
Terje Slettebø <tslettebo@broadpark.no> writes:
// int_vector r_list = to_runtime<c_list>();
int_vector r_list;
boost::mpl::for_each<c_list>(to_sequence<int_vector>(r_list));
Better yet:
int_vector r_list; boost::mpl::for_each<c_list>(std::back_inserter(r_list));
Enjoy ;-)
Um, how does this work? back_inserter returns an iterator, not a function object; is there some magic in mpl::for_each that I can't see? Maybe I'm looking at the wrong version?
No, I'm just an idiot :(. Please ignore my post. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams writes:
"Peter Dimov" <pdimov@mmltd.net> writes:
David Abrahams wrote:
Terje Slettebø <tslettebo@broadpark.no> writes:
// int_vector r_list = to_runtime<c_list>();
int_vector r_list;
boost::mpl::for_each<c_list>(to_sequence<int_vector>(r_list));
Better yet:
int_vector r_list; boost::mpl::for_each<c_list>(std::back_inserter(r_list));
Enjoy ;-)
Um, how does this work? back_inserter returns an iterator, not a function object; is there some magic in mpl::for_each that I can't see? Maybe I'm looking at the wrong version?
No, I'm just an idiot :(. Please ignore my post.
This should work, though: int_vector r_list; boost::mpl::for_each<c_list>( boost::bind(&int_vector::push_back, &r_list, _1) ); -- Aleksey Gurtovoy MetaCommunications Engineering

From: "Peter Dimov" <pdimov@mmltd.net>
David Abrahams wrote:
Terje Slettebø <tslettebo@broadpark.no> writes:
// int_vector r_list = to_runtime<c_list>();
int_vector r_list;
boost::mpl::for_each<c_list>(to_sequence<int_vector>(r_list));
Better yet:
int_vector r_list; boost::mpl::for_each<c_list>(std::back_inserter(r_list));
Enjoy ;-)
Um, how does this work? back_inserter returns an iterator, not a function object; is there some magic in mpl::for_each that I can't see? Maybe I'm looking at the wrong version?
Apparently not. However, you can always adapt one to the other, but I don't know if that's an improvement: template<class Iterator> class iterator_to_functor_type { public: iterator_to_functor_type(const Iterator &i) : iterator(i) {} template<class Element> void operator()(Element e) { *iterator=e; ++iterator; } private: Iterator iterator; }; template<class Iterator> iterator_to_functor_type<Iterator> iterator_to_functor(const Iterator &i) { return iterator_to_functor_type<Iterator>(i); } boost::mpl::for_each<c_list>(iterator_to_functor(std::back_inserter(r_list)) ); The behaviour of mpl::for_each is consistent with std::for_each, as both takes a function (object) where each element is passed to. However, thinking more about this fusion of compile-time and run-time, how about having an MPL copy function, that copies from a compile-time sequence, to a run-time sequence (or vice versa)? With it, one could use all the arsenal of the standard library using iterators, including iterator adapters for insertion and streams: template<class Sequence,class Iterator> void copy(const Iterator &i) { boost::mpl::for_each<Sequence>(iterator_to_functor(i)); } This way, we get: copy<c_list>(std::back_inserter(r_list)); Simple and clear. Output of a compile-time sequence is also trivial: copy<c_list>(std::ostream_iterator<int>(std::cout,",")); Could we have this, please? :) Now, I know that we can't overload class templates (can we do something about that?), so this has to be called something else than "copy", as there's already one in MPL, or one might use partial specialisation to enable them to coexist. Regards, Terje

From: "Terje Slettebø" <tslettebo@broadpark.no>
This way, we get:
copy<c_list>(std::back_inserter(r_list));
Output of a compile-time sequence is also trivial:
copy<c_list>(std::ostream_iterator<int>(std::cout,","));
Thinking about this some more, the only reason this works is that the sequence consists of elements of the same type (integral_c derived), and that it has an implicit conversion to the value type. However, it would also be possible to support heterogenous sequences, but then, the standard iterator adapters aren't sufficient, as they only work for homogenous sequences. That's possible to make, though. For fun, I knocked up this program, which stores values of a variety of types in a compile-time sequence (char, int, double, rational_c and std::string (wrapped)), prints the sequence out, copies it to a run-time sequence (using boost::variant as element type), and prints it out, again. It has been tested on Intel C++ 7.1 and g++ 3.2. --- Start --- #include <iostream> #include <string> #include <vector> #include <iterator> #include <algorithm> #include <boost/variant.hpp> #include <boost/mpl/vector.hpp> #include <boost/mpl/integral_c.hpp> #include <boost/mpl/int.hpp> #include <boost/mpl/for_each.hpp> namespace boost { // There's a name-lookup problem finding the string stream operator, so we provide a forwarding function std::ostream &operator<<(std::ostream &stream,const std::string &s) { std::operator<<(stream,s); return stream; } // Iterator to function object conversion template<class Iterator> class iterator_to_functor_type { public: iterator_to_functor_type(const Iterator &i) : iterator(i) {} template<class Element> void operator()(Element e) { *iterator=e; ++iterator; } private: Iterator iterator; }; template<class Iterator> iterator_to_functor_type<Iterator> iterator_to_functor(const Iterator &i) { return iterator_to_functor_type<Iterator>(i); } // An ostream_iterator for heterogenous sequences class ostream_iterator { public: ostream_iterator(std::ostream &s,const char *d) : stream(s),delimiter(d) {} ostream_iterator operator*() const { return *this; } ostream_iterator operator++() { return *this; } template<class T> void operator=(const T &value) { stream << value << delimiter; } private: std::ostream &stream; const char *delimiter; }; namespace mpl { // A rational_c type that works like integral_c (one may also use ref, below) template<class FloatType,class IntType,IntType N,IntType D> struct rational_c { operator FloatType() const { return static_cast<FloatType>(N)/D; } }; // A compile-time reference wrapper, for types that can't be passed as non-type template parameters template<class T,T &value> struct ref { operator T() const { return value; } }; // copy compile-time to run-time sequence template<class Sequence,class Iterator> void copy(const Iterator &i) { boost::mpl::for_each<Sequence>(iterator_to_functor(i)); } } // namespace mpl } // namespace boost using namespace boost; double pi=3.14; std::string s("Test"); int main() { typedef mpl::vector< mpl::integral_c<char,'A'>, mpl::int_<123>, mpl::rational_c<double,int,1,2>, mpl::ref<double,pi>, mpl::ref<std::string,s>
c_list;
// Print compile-time sequence - "A,123,0.5,3.14,Test" mpl::copy<c_list>(ostream_iterator(std::cout,",")); typedef variant<char,int,double,std::string> element_type; std::vector<element_type> r_list; // Copy from compile-time to run-time sequence mpl::copy<c_list>(std::back_inserter(r_list)); // Print run-time sequence - "A,123,0.5,3.14,Test" std::copy(r_list.begin(),r_list.end(),ostream_iterator(std::cout,",")); } --- End --- Regards, Terje

Terje Slettebø <tslettebo@broadpark.no> writes:
From: "Terje Slettebø" <tslettebo@broadpark.no>
This way, we get:
copy<c_list>(std::back_inserter(r_list));
Output of a compile-time sequence is also trivial:
copy<c_list>(std::ostream_iterator<int>(std::cout,","));
Thinking about this some more, the only reason this works is that the sequence consists of elements of the same type (integral_c derived), and that it has an implicit conversion to the value type.
However, it would also be possible to support heterogenous sequences, but then, the standard iterator adapters aren't sufficient, as they only work for homogenous sequences. That's possible to make, though.
For fun, I knocked up this program, which stores values of a variety of types in a compile-time sequence (char, int, double, rational_c and std::string (wrapped)), prints the sequence out, copies it to a run-time sequence (using boost::variant as element type), and prints it out, again.
You seem to be treading heavily into the territory of boost::fusion here, no? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

From: "David Abrahams" <dave@boost-consulting.com>
Terje Slettebø <tslettebo@broadpark.no> writes:
From: "Terje Slettebø" <tslettebo@broadpark.no>
This way, we get:
copy<c_list>(std::back_inserter(r_list));
Output of a compile-time sequence is also trivial:
copy<c_list>(std::ostream_iterator<int>(std::cout,","));
Thinking about this some more, the only reason this works is that the sequence consists of elements of the same type (integral_c derived), and that it has an implicit conversion to the value type.
However, it would also be possible to support heterogenous sequences, but then, the standard iterator adapters aren't sufficient, as they only work for homogenous sequences. That's possible to make, though.
For fun, I knocked up this program, which stores values of a variety of types in a compile-time sequence (char, int, double, rational_c and std::string (wrapped)), prints the sequence out, copies it to a run-time sequence (using boost::variant as element type), and prints it out, again.
You seem to be treading heavily into the territory of boost::fusion here, no?
That's hard to tell, given that there's hardly any docs on boost::fusion (however, the library was on my mind when I mentioned "fusion of compile-time and run-time" in an earlier posting, since that says in fusion's docs. I didn't think this was anybody's territory in particular, though (it seems very broad)). However, looking at the fusion docs, again, it seems you're right. What I had originally thought about, was MPL (where this thread originated). However, as you say, boost::fusion might be more appropriate for it. The above was only meant for inspiration and fun. If this functionality, or something like it, already exists in boost::fusion, then great. However, complaining about me treading into another library's territory, when I haven't found any fence (docs, showing me that this exist already), seems a bit unfair. (Maybe it wasn't meant as complaint, but it seemed that way. If you had just mentioned that this exists in boost::fusion, or it may be more appropriate for it, I wouldn't had a problem with it.) Regards, Terje

Terje Slettebø <tslettebo@broadpark.no> writes:
Maybe it wasn't meant as complaint, but it seemed that way. If you had just mentioned that this exists in boost::fusion, or it may be more appropriate for it, I wouldn't had a problem with it.
It wasn't meant as a complaint. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

From: "David Abrahams" <dave@boost-consulting.com>
Terje Slettebø <tslettebo@broadpark.no> writes:
Maybe it wasn't meant as complaint, but it seemed that way. If you had just mentioned that this exists in boost::fusion, or it may be more appropriate for it, I wouldn't had a problem with it.
It wasn't meant as a complaint.
Then I have no problem with it. (In retrospective, I should just have written "The above was only meant for inspiration and fun. If this functionality, or something like it, already exists in boost::fusion, then great.", and left it at that.) Best regards, Terje
participants (5)
-
Aleksey Gurtovoy
-
David Abrahams
-
Jaap Suter
-
Peter Dimov
-
Terje Slettebø