MPL to get rid of cumbersome switch

Hi; The program belows compiles and works but I'd like to simplify it, maybe using MPL. I spent some fascinating time educating myself on MPL, reading C++ Template Metaprogramming, but I am still at sea... to say the least. Basically the Functor contains a switch statement that is not convenient especially as the number of T classes will increase dramatically. Many thanks for any help on that JCR #include <iostream> #include <vector> #include <boost/mpl/vector.hpp> struct Tbase { Tbase() { std::cout << "Tbase" << std::endl; } }; struct T0 : public Tbase { T0() { std::cout << "T0" << std::endl; } }; struct T1 : public Tbase { T1() { std::cout << "T1" << std::endl; } }; typedef boost::mpl::vector<T0, T1> s; std::vector<Tbase*> vec; struct Functor { void operator()(const int& i) { switch(i) { case 0: vec.push_back(new T0); break; case 1: vec.push_back(new T1); break; } // I'd like to simplify the above swtich statement by writing something like: vec.push_back(new boost::mpl::at<s,i>::type); // but it does not compile and MinGW returns: // error: i cannot appear in a constant expression // error: template argument 2 is invalid. } }; int main (int argc, char ** argv) { std::vector<int> runtimeVec; runtimeVec.push_back(0); runtimeVec.push_back(1); runtimeVec.push_back(0); std::for_each(runtimeVec.begin(), runtimeVec.end(), Functor()); std::cout << vec.size() << std::endl; return 0; }

On Thu, 16 Mar 2006, John Christopher wrote:
void operator()(const int& i) { switch(i) { case 0: vec.push_back(new T0); break; case 1: vec.push_back(new T1); break; } // I'd like to simplify the above swtich statement by writing something like: vec.push_back(new boost::mpl::at<s,i>::type); // but it does not compile and MinGW returns: // error: i cannot appear in a constant expression // error: template argument 2 is invalid. }
Of course it doesn't compile, because non-type template arguments must be constants known at compile time. However here, the parameter i isn't, and thus cannot be used as a template argument. It would seem like you are stuck with a switch, unless you create something like an array of generating function, e.g.: template < typename T > Tbase* genT() { return new T ; } typedef Tbase* (* genT_type)() ; genT_type generators[] = { & genT< T0 > , & genT< T1 > } ; //... void operator () ( const int i ) { vec.push_back( generators[ i ]() ) ; } It won't be as efficient as the switch though because of the function call through a function pointer. -- François Duranleau LIGUM, Université de Montréal "A person's truth is so simple that most ignore it to concentrate on what they think are deeper truths." - from _Neon Genesis Evangelion_

François Duranleau <duranlef@iro.umontreal.ca> writes:
On Thu, 16 Mar 2006, John Christopher wrote:
void operator()(const int& i) { switch(i) { case 0: vec.push_back(new T0); break; case 1: vec.push_back(new T1); break; } // I'd like to simplify the above swtich statement by writing something like: vec.push_back(new boost::mpl::at<s,i>::type); // but it does not compile and MinGW returns: // error: i cannot appear in a constant expression // error: template argument 2 is invalid. }
Of course it doesn't compile, because non-type template arguments must be constants known at compile time. However here, the parameter i isn't, and thus cannot be used as a template argument. It would seem like you are stuck with a switch, unless you create something like an array of generating function, e.g.:
template < typename T > Tbase* genT() { return new T ; }
typedef Tbase* (* genT_type)() ; genT_type generators[] = { & genT< T0 > , & genT< T1 > } ;
//... void operator () ( const int i ) { vec.push_back( generators[ i ]() ) ; }
It won't be as efficient as the switch though because of the function call through a function pointer.
Chapter 11 of "C++ Template Metaprogramming" shows how to generate the equivalent of a switch statement using the MPL. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On Thu, 16 Mar 2006, David Abrahams wrote:
Chapter 11 of "C++ Template Metaprogramming" shows how to generate the equivalent of a switch statement using the MPL.
I will need to save up some money to get that book. -- François Duranleau LIGUM, Université de Montréal "Conflict may erupt at any time and any place. War is the destiny of which humanity can never wash its hands." - Emperor Dornkirk, in _The Vision of Escaflowne_

Hello, Still reading... Chapter 11 is still a few pages away... Any way, I rewrote the program and I have something much simpler. The vector of types has not changed: typedef boost::mpl::vector<T0, T1, T2, T3> TTypes; but the Functor has a new switch statement that is much easier to maintain. The nnumber of cases in the switch must be the number of elements in the vector of types... Adding new cases is no big deal anyway. switch(i) { case 0: vec.push_back(new boost::mpl::at<TTypes, boost::mpl::int_<0> >::type); break; case 1: vec.push_back(new boost::mpl::at<TTypes, boost::mpl::int_<1> >::type); break; .... JCR #include <iostream> #include <vector> #include <boost/mpl/vector.hpp> #include <boost/mpl/at.hpp> struct Tbase { virtual void display() = 0; virtual ~Tbase() = 0; }; inline Tbase::~Tbase() { } struct T0 : public Tbase { virtual void display() { std::cout << "display T0" << std::endl; } }; struct T1 : public Tbase { virtual void display() { std::cout << "display T1" << std::endl; } }; struct T2 : public Tbase { virtual void display() { std::cout << "display T2" << std::endl; } }; struct T3 : public Tbase { virtual void display() { std::cout << "display T3" << std::endl; } }; typedef boost::mpl::vector<T0, T1, T2, T3> TTypes; std::vector<Tbase*> vec; struct Functor { void operator()(const int& i) { switch(i) { case 0: vec.push_back(new boost::mpl::at<TTypes, boost::mpl::int_<0>
::type); break; case 1: vec.push_back(new boost::mpl::at<TTypes, boost::mpl::int_<1> ::type); break; case 2: vec.push_back(new boost::mpl::at<TTypes, boost::mpl::int_<2> ::type); break; case 3: vec.push_back(new boost::mpl::at<TTypes, boost::mpl::int_<3> ::type); break; } } }; struct Display { void operator() (Tbase* p) { p->display(); } }; struct Clean { void operator() (Tbase* p) { delete p; } }; int main (int argc, char ** argv) { std::vector<int> runtimeVec; runtimeVec.push_back(3); runtimeVec.push_back(0); runtimeVec.push_back(0); std::for_each(runtimeVec.begin(), runtimeVec.end(), Functor()); std::cout << vec.size() << std::endl; std::for_each(vec.begin(), vec.end(), Display()); std::for_each(vec.begin(), vec.end(), Clean()); return 0; }
"François Duranleau" <duranlef@iro.umontreal.ca> wrote in message news:Pine.LNX.4.63.0603171314001.25367@brocoli.iro.umontreal.ca... On Thu, 16 Mar 2006, David Abrahams wrote:
Chapter 11 of "C++ Template Metaprogramming" shows how to generate the equivalent of a switch statement using the MPL.
I will need to save up some money to get that book. -- François Duranleau LIGUM, Université de Montréal "Conflict may erupt at any time and any place. War is the destiny of which humanity can never wash its hands." - Emperor Dornkirk, in _The Vision of Escaflowne_ --------------------------------------------------------------------------------
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

John Christopher wrote:
Hello, Still reading... Chapter 11 is still a few pages away... Any way, I rewrote the program and I have something much simpler. The vector of types has not changed: typedef boost::mpl::vector<T0, T1, T2, T3> TTypes; but the Functor has a new switch statement that is much easier to maintain. The nnumber of cases in the switch must be the number of elements in the vector of types... Adding new cases is no big deal anyway. switch(i) { case 0: vec.push_back(new boost::mpl::at<TTypes, boost::mpl::int_<0> >::type); break; case 1: vec.push_back(new boost::mpl::at<TTypes, boost::mpl::int_<1> >::type); break; ....
Given its prepetitive nature you could use boost preprocessor library to generate this switch... -delfin

Given its prepetitive nature you could use boost preprocessor library to generate this switch...
::type); \ break; BOOST_PP_REPEAT(NUMBER_CASES, CASES, ~); }
That's a good idea. I could define #define NUMBER_CASES 4 and the switch would become something like that: switch(i) { #define CASES(z, n, text) \ case n: \ vec.push_back(new boost::mpl::at<TTypes, boost::mpl::int_<n> this compiles and works fine, but, since the number of cases in the switch must equal the size of the vector of type, I'd rather write something like: #define NUMBER_CASES boost::mpl::size<TTypes>::value but this does not compile and I am getting the error C:/ventures/test/classes/main.cpp: In member function `void Functor::operator()(const int&)': C:/ventures/test/classes/main.cpp:47: error: `BOOST_PP_REPEAT_1_boost' has not been declared C:/ventures/test/classes/main.cpp:47: error: `size' undeclared (first use this function) C:/ventures/test/classes/main.cpp:47: error: (Each undeclared identifier is reported only once for each function it appears in.) C:/ventures/test/classes/main.cpp:47: error: expected primary-expression before '>' token C:/ventures/test/classes/main.cpp:47: error: `::value' has not been declared C:/ventures/test/classes/main.cpp:47: error: `CASES' undeclared (first use this function) C:/ventures/test/classes/main.cpp:47: error: expected primary-expression before ')' token mingw32-make[1]: *** [release\main.o] Error 1 Any idea on how to make it work? Many thanks JCR "Delfin Rojas" <drojas@moodlogic.com> wrote in message news:005001c64a19$6ed5c8e0$3000a8c0@winxpme...
John Christopher wrote:
Hello, Still reading... Chapter 11 is still a few pages away... Any way, I rewrote the program and I have something much simpler. The vector of types has not changed: typedef boost::mpl::vector<T0, T1, T2, T3> TTypes; but the Functor has a new switch statement that is much easier to maintain. The nnumber of cases in the switch must be the number of elements in the vector of types... Adding new cases is no big deal anyway. switch(i) { case 0: vec.push_back(new boost::mpl::at<TTypes, boost::mpl::int_<0> >::type); break; case 1: vec.push_back(new boost::mpl::at<TTypes, boost::mpl::int_<1> >::type); break; ....
Given its prepetitive nature you could use boost preprocessor library to generate this switch...
-delfin

-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] On Behalf Of John Christopher Sent: Saturday, March 18, 2006 8:26 AM To: boost-users@lists.boost.org Subject: Re: [Boost-users] MPL to get rid of cumbersome switch
Given its prepetitive nature you could use boost preprocessor library to generate this switch...
That's a good idea. I could define #define NUMBER_CASES 4 and the switch would become something like that: switch(i) { #define CASES(z, n, text) \ case n: \ vec.push_back(new boost::mpl::at<TTypes, boost::mpl::int_<n> >::type); \ break; BOOST_PP_REPEAT(NUMBER_CASES, CASES, ~); } this compiles and works fine, but, since the number of cases in the switch must equal the size of the vector of type, I'd rather write something like: #define NUMBER_CASES boost::mpl::size<TTypes>::value
but this does not compile and I am getting the error
Yeah, that won't work because the preprocessor cannot evaluate 'boost::mpl::size<TTypes>::value'. If you're going to use the preprocessor for this, you need to store the types in a preprocessor data structure, not an mpl::vector. (Note, BTW, than an MPL vector can be trivial created from a preprocessor data structure.) Regards, Paul Mensonides

"Paul Mensonides" <pmenso57@comcast.net> writes:
Yeah, that won't work because the preprocessor cannot evaluate 'boost::mpl::size<TTypes>::value'. If you're going to use the preprocessor for this, you need to store the types in a preprocessor data structure, not an mpl::vector. (Note, BTW, than an MPL vector can be trivial created from a preprocessor data structure.)
If you don't want to do that, you'll have to resort to generating a chained "if" set of inline function calls containing "if" statements. Unless there are many cases, that may be as fast as a case statement. -- Dave Abrahams Boost Consulting www.boost-consulting.com

"Paul Mensonides" wrote:
Yeah, that won't work because the preprocessor cannot evaluate 'boost::mpl::size<TTypes>::value'. If you're going to use the preprocessor for this, you need to store the types in a preprocessor data structure, not an mpl::vector. (Note, BTW, than an MPL vector can be trivial created from a preprocessor data structure.)
Thanks for the idea; the program compiles and works fine; it is easy to maintain since I have only the preprocessor data structure to keep updated when I add T classes. I am getting some type checking for instance if I add to the TYPES preprocessor data structure a type that does not exist. MPL and preprocesor library are great tools! JCR #define MY_TYPES (T0) (T1) (T2) (T3) (T4) typedef boost::mpl::vector<BOOST_PP_SEQ_ENUM(MY_TYPES)> TTypes; struct Functor { void operator()(const int& i) { switch(i) { #define CASES(z, n, text) \ case n: \ vec.push_back(new boost::mpl::at<TTypes, boost::mpl::int_<n>
::type); \ break; BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(MY_TYPES), CASES, ~); } } };
"Paul Mensonides" <pmenso57@comcast.net> wrote in message news:20060319010923.420C61055A1@wowbagger.osl.iu.edu...
-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] On Behalf Of John Christopher Sent: Saturday, March 18, 2006 8:26 AM To: boost-users@lists.boost.org Subject: Re: [Boost-users] MPL to get rid of cumbersome switch
Given its prepetitive nature you could use boost preprocessor library to generate this switch...
That's a good idea. I could define #define NUMBER_CASES 4 and the switch would become something like that: switch(i) { #define CASES(z, n, text) \ case n: \ vec.push_back(new boost::mpl::at<TTypes, boost::mpl::int_<n> >::type); \ break; BOOST_PP_REPEAT(NUMBER_CASES, CASES, ~); } this compiles and works fine, but, since the number of cases in the switch must equal the size of the vector of type, I'd rather write something like: #define NUMBER_CASES boost::mpl::size<TTypes>::value
but this does not compile and I am getting the error
Yeah, that won't work because the preprocessor cannot evaluate 'boost::mpl::size<TTypes>::value'. If you're going to use the preprocessor for this, you need to store the types in a preprocessor data structure, not an mpl::vector. (Note, BTW, than an MPL vector can be trivial created from a preprocessor data structure.)
Regards, Paul Mensonides
participants (5)
-
David Abrahams
-
Delfin Rojas
-
François Duranleau
-
John Christopher
-
Paul Mensonides