MPL to get rid of cumbersome switch

classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

MPL to get rid of cumbersome switch

Jean-Christophe Roux
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;
}



_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: MPL to get rid of cumbersome switch

François Duranleau
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_
_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: MPL to get rid of cumbersome switch

David Abrahams
François Duranleau <[hidden email]> 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

_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: MPL to get rid of cumbersome switch

François Duranleau
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
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: MPL to get rid of cumbersome switch

Jean-Christophe Roux
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" <[hidden email]> wrote in message
news:[hidden email]...
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
> [hidden email]
> http://lists.boost.org/mailman/listinfo.cgi/boost-users 




_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: MPL to get rid of cumbersome switch

Delfin Rojas
> 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

_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: MPL to get rid of cumbersome switch

Jean-Christophe Roux
> 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
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" <[hidden email]> 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



_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: MPL to get rid of cumbersome switch

Paul Mensonides
 

> -----Original Message-----
> From: [hidden email]
> [mailto:[hidden email]] On Behalf Of
> John Christopher
> Sent: Saturday, March 18, 2006 8:26 AM
> To: [hidden email]
> 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

_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: MPL to get rid of cumbersome switch

David Abrahams
"Paul Mensonides" <[hidden email]> 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

_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: MPL to get rid of cumbersome switch

Jean-Christophe Roux
In reply to this post by Paul Mensonides
"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" <[hidden email]> wrote in message
news:[hidden email]...

>
>
>> -----Original Message-----
>> From: [hidden email]
>> [mailto:[hidden email]] On Behalf Of
>> John Christopher
>> Sent: Saturday, March 18, 2006 8:26 AM
>> To: [hidden email]
>> 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



_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users