[mpl] looping over a list of types inside a function

Hello, I would like to be able to write code like this: int i; for F in LIST_OF_TYPES complicated_function<F>(i); where this code is inside some other function which is inside a class templatized over LIST_OF_TYPES. Given the lack of nested functions and classes in C++ functions, am I correct in thinking that it's impossible to do this sort of thing inside another function? In my particlar case, all the complicated code has already been factored into complicated_function, and there are only ever two LISTS_OF_TYPES, so my current solution is just to manually specialize over LISTS_OF_TYPES. However, this kind of construct often appears several times (with different complicated_functions) in a given outer function, so it would be very nice to only have to write down the high level structure once. Thanks, Geoffrey

I think you should be able to do something computationally equivalent. I'd try for a variant of tail recursion where you have a complex_functor that does something like complicated_function< mpl::front<L>::type > (i); mpl::if size<L> > 1 complicated_functor< mpl::pop_front<L>::type > (i); Then you invoke this instead of the "for" loop. I haven't looked too closely but mpl::fold might already do this kind of thing. At 11:21 AM 8/26/2005, you wrote:
Hello,
I would like to be able to write code like this:
int i; for F in LIST_OF_TYPES complicated_function<F>(i);
where this code is inside some other function which is inside a class templatized over LIST_OF_TYPES. Given the lack of nested functions and classes in C++ functions, am I correct in thinking that it's impossible to do this sort of thing inside another function?
In my particlar case, all the complicated code has already been factored into complicated_function, and there are only ever two LISTS_OF_TYPES, so my current solution is just to manually specialize over LISTS_OF_TYPES. However, this kind of construct often appears several times (with different complicated_functions) in a given outer function, so it would be very nice to only have to write down the high level structure once.
Thanks, Geoffrey _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Thanks! I knew something like could be written, but for some reason I thought there'd be significantly more overhead in turning a function into something loopable. It's unfortunate that one can't pass a function template as a template argument, since that would remove the need for the extra functor class entirely. Geoffrey On Fri, Aug 26, 2005 at 04:24:36PM -0500, Alan M. Carroll wrote:
Here's some code I whipped out that does what you want, although I'm sure it could be done better (it was an interesting learning exercise, though)
# include <boost/mpl/if.hpp> # include <boost/mpl/list.hpp> # include <boost/mpl/empty.hpp> # include <boost/mpl/front.hpp> # include <boost/mpl/pop_front.hpp>
// this is the thing we want to call on the types // We don't put it in the functor so that it can be specialized in multiple places template < typename T > void complicated_function( int i) { std::cout << "i = " << i << " sizeof = " << sizeof (T) << std::endl; }
// need this as a simple type so we can pass it to chain struct functor { template < typename T > void operator () (int i) const { complicated_function<T>(i); } };
// do tail recursion on L using the functor F template < typename F , typename L > struct chain { struct tail { void operator () (int i) const { return ; } }; struct main { void operator () (int i) const { F f; f. operator ()<boost::mpl::front<L>::type >(i); chain<F, boost::mpl::pop_front<L>::type>()(i); } }; void operator () (int i) const { boost::mpl::if_c<boost::mpl::empty<L>::value, tail, main >::type ()(i); } };
// A list of types to use typedef boost::mpl::list< int, double , char , std::string> the_list;
// demonstrate that we're calling complicated_function for each type in the list void mpl_test() { chain<functor, the_list>()(17); }

On Sun, Aug 28, 2005 at 11:50:28AM -0500, Alan M. Carroll wrote:
I couldn't resist figuring out how to take advantage of boost::mpl::fold, which seemed very close to what I wanted. I've attached a (IMHO) superior version that takes better advantage of Boost.MPL. It uses only one adjunct struct, eliminating the extra functor class and being overall simpler and shorter. I ran this successfully using MSVC 71. I have to say, I can't imagine doing much better than this. MPL rocks.
Alas, eliminating the extra functor that way doesn't help, since in my case I have to apply this construct to a slew of functions (this is for a water simulator where we often have to do something for x,y in 2d or x,y,z in 3d). Happily, the annoyance of the extra helper structs is nothing in comparison to the fact that this let me replace 18 source files with 6 (2/3's of the files were 2d/3d stubs). Thanks, Geoffrey
# include <boost/mpl/list.hpp> # include <boost/mpl/fold.hpp>
// The complicated function to call for each type. // Top level template so it can be specialized in // multiple locations. template < typename T > void complicated_function( int i) { std::cout << "i = " << i << " sizeof = " << sizeof (T) << std::endl; }
// Support metafunction that adds a call to an existing // chain of calls struct chain { template < typename R, // the accumulated chain typename T // a type from the list > struct apply { // make this a Boost.MPL metafunction // the result from the application of the metafunction, // a functor that combines the chain in to one call. struct type { void operator () (int i) const { typename R()(i); // do the existing chain // add our type specialized call complicated_function< typename T>(i); } }; }; // fold requires an initial state, for which we // provide this do nothing call. It's possible // optimize away the need for this but I think // that is more trouble than it is worth. struct no_op { void operator () (int i) const { return ; }}; };
void test_mpl() { // create the list of types. typedef boost::mpl::list< int, char , float , std::string> the_list; // create the chain of calls from the list typedef boost::mpl::fold<the_list, chain::no_op, chain>::type invocation; // call the chain. invocation()(56); }

Geoffrey Irving <irving@cs.stanford.edu> writes:
Hello,
I would like to be able to write code like this:
int i; for F in LIST_OF_TYPES complicated_function<F>(i);
where this code is inside some other function which is inside a class templatized over LIST_OF_TYPES. Given the lack of nested functions and classes in C++ functions, am I correct in thinking that it's impossible to do this sort of thing inside another function?
Okay, what's wrong with boost::mpl::for_each? Argh, no wonder! Why isn't that in the reference manual? I'm afraid you'll have to read http://www.boost-consulting.com/mplbook for documentaiton on for_each :( This general approach should work: // Just in case T can't be constructed and passed by value template <class T> struct wrap {}; struct call_complicated { // You could also use boost::bind for this call_complicated(int i) : i(i) {} int i; template <class T> void operator()(wrap<T>) const { complicated_function<T>(i); } }; template <class list_of_types> class foo { void some_function() { int i; mpl::for_each<list_of_types, wrap<mpl::_1> >( call_complicated(i) ); } }; HTH, -- Dave Abrahams Boost Consulting www.boost-consulting.com
participants (3)
-
Alan M. Carroll
-
David Abrahams
-
Geoffrey Irving