[boost-users] How to put together a tuple type?

Hi there, just trying to figure out how to put together a tuple type at compile type? Please consider the following code: struct s1 { static const int num_values = 1; int i; }; struct s2 { static const int num_values = 2; int i; int j; }; struct s3 { static const int num_values = 3; int i; int j; int k; }; template< class S > void create_tuple( S s ) { /// create tuple_type map< tuple_type, unsigned int > map; map[ make_tuple( s ) ] = 99; } The template parameter S will only be one of above defined structs. Clearly, I need to loop over S::num_values to create the tuple type. But how do I do that? Thanks ahead, Christian

On 8/15/06, Christian Henning <chhenning@gmail.com> wrote:
The template parameter S will only be one of above defined structs. Clearly, I need to loop over S::num_values to create the tuple type. But how do I do that?
What about using a boost::array<int,S::num_values> instead? It's not exactly what you're asking, but it might solve the problem... ~ Scott McMurray

That's work in my sample code. Thanks. But what happens if the S structs are more heterogenious? Like: struct s3 { static const int num_values = 4; int i; float j; int k; double l; }; I'm sure there is some mpl magic possible. Regards, Christian

Christian Henning wrote:
That's work in my sample code. Thanks.
But what happens if the S structs are more heterogenious? Like:
struct s3 { static const int num_values = 4;
int i; float j; int k; double l; };
I'm sure there is some mpl magic possible.
Fusion! :-) mpl::vector_c<4> consts; fusion::vector<int, float, int, double> vars; fusion::joint_view<consts, vars> s3(consts, vars); Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
Christian Henning wrote:
That's work in my sample code. Thanks.
But what happens if the S structs are more heterogenious? Like:
struct s3 { static const int num_values = 4;
int i; float j; int k; double l; };
I'm sure there is some mpl magic possible.
Fusion! :-)
mpl::vector_c<4> consts; fusion::vector<int, float, int, double> vars; fusion::joint_view<consts, vars> s3(consts, vars);
Oops, that should be typedef mpl::vector_c<int, 4> consts_type; typedef fusion::vector<int, float, int, double> vars_type; vars_type vars; fusion::joint_view<consts_type, vars_type> s3(consts_type(), vars); Anyway, I'm sure you got the point. With our 's3' above, we can, for exemple, write (using boost::lambda): fusion::for_each(s3, cout << _1 << endl); to print all the items. I'll be putting Fusion in the Boost CVS soon. Try it! :) Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Hi Joel,
Oops, that should be
typedef mpl::vector_c<int, 4> consts_type; typedef fusion::vector<int, float, int, double> vars_type;
vars_type vars; fusion::joint_view<consts_type, vars_type> s3(consts_type(), vars);
Anyway, I'm sure you got the point. With our 's3' above, we can, for exemple, write (using boost::lambda):
fusion::for_each(s3, cout << _1 << endl);
to print all the items.
I just tried your suggestion and it works until the fusion::for_each() call. There, I get a million compiler errors. I'm sure I'm must missing something simple here. This is what I'm doing: #include <iostream> #include <tchar.h> #include <boost/lambda/lambda.hpp> #include <boost/mpl/vector_c.hpp> #include <boost/fusion/algorithm.hpp> #include <boost/fusion/sequence.hpp> using namespace std; using namespace boost; using namespace boost::lambda; struct s1 { static const int num_values = 1; int i; }; struct s2 { static const int num_values = 2; int i; int j; }; struct s3 { static const int num_values = 3; int i; int j; int k; }; struct s4 { static const int num_values = 4; int i; float j; int k; double l; }; template <class S> void doSomething( S& s ) { typedef mpl::vector_c<int, 4> consts_type; typedef fusion::vector<int, float, int, double> vars_type; vars_type vars; fusion::joint_view<consts_type, vars_type> view(consts_type(), vars); fusion::for_each( view, cout << _1 << endl ); } int _tmain(int argc, _TCHAR* argv[]) { s4 s; doSomething( s ); return 0; } When I got the CVS head there was no fusion documentation included. Is that correct? Greets, Christian

Christian Henning wrote:
Hi Joel,
Oops, that should be
typedef mpl::vector_c<int, 4> consts_type; typedef fusion::vector<int, float, int, double> vars_type;
vars_type vars; fusion::joint_view<consts_type, vars_type> s3(consts_type(), vars);
Anyway, I'm sure you got the point. With our 's3' above, we can, for exemple, write (using boost::lambda):
fusion::for_each(s3, cout << _1 << endl);
to print all the items.
I just tried your suggestion and it works until the fusion::for_each() call. There, I get a million compiler errors. I'm sure I'm must missing something simple here.
This is what I'm doing:
[snip code] My mistake. The code should be: typedef mpl::vector_c<int, 4> consts_type; typedef fusion::vector<int, float, int, double> vars_type; consts_type consts; vars_type vars; fusion::joint_view<consts_type, vars_type> view(consts, vars); fusion::for_each( view, cout << _1 << "\n" ); (Sometimes I can't figure out various aspects of lambda. Here, it can't grok std::endl. Anyway, that's an unrelated issue. You can simply throw in your function/function-object there.)
When I got the CVS head there was no fusion documentation included. Is that correct?
It's there now. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Thanks, that worked now. I like the fusion::for_each loop, it's very handy! Anyway, when I started this thread I actually had something else in my mind. As you can see the doSomething() is templated. I would like to create a type vector depending on the template parameter, here S. Is that possible? I could image to have something like this ( beware bad pseudo code ): template <class S> void doSomething( S& s ) { //create vector depending on S's length typedef fusion::vector<S::num_values> vec; // vector length // add the members type to vec fusion::for_each_member( s, vec.add() ); // create boost tuple type out of vec fusion::make_tuple( vec ); } Am I totally fantasying here? I think all the infomation are available at compile time. Thanks again, Christian

Christian Henning wrote:
Thanks, that worked now. I like the fusion::for_each loop, it's very handy!
Anyway, when I started this thread I actually had something else in my mind. As you can see the doSomething() is templated. I would like to create a type vector depending on the template parameter, here S. Is that possible?
I could image to have something like this ( beware bad pseudo code ):
template <class S> void doSomething( S& s ) { //create vector depending on S's length typedef fusion::vector<S::num_values> vec; // vector length
// add the members type to vec fusion::for_each_member( s, vec.add() );
// create boost tuple type out of vec fusion::make_tuple( vec ); }
Am I totally fantasying here? I think all the infomation are available at compile time.
Creating a type vector depending on the template parameter, S, is certainly OK. I'll have to ignore the "bad pseudo code" though ;) You have to do it another way. Tell me precisely what you wish to do and I may be able to provide an example. Actually, I am compiling a small set of simple use-case examples. You wouldn't mind if I use our first example, would you? Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Creating a type vector depending on the template parameter, S, is certainly OK. I'll have to ignore the "bad pseudo code" though ;) You have to do it another way. Tell me precisely what you wish to do and I may be able to provide an example. Actually, I am compiling a small set of simple use-case examples. You wouldn't mind if I use our first example, would you?
No, of course not. How about a real life example? I trying to create a generic histogram operator for GIL ( Generic Image Library - see http://opensource.adobe.com/gil/index.html ). To create a histogram I need to count all colors of an image and put them into a map. Since there are many different color definitions, like rgb-8bit, cymk32, gray-8bit, etc., I was intend to create the key type of the histogram map as a tuple. For example: struct rgb8 { static const int num_channels = 3; unsigned char red; unsigned char green; unsigned char blue; }; struct cymk32 { static const int num_channels = 4; unsigned int cyan; unsigned int yellow; unsigned int magenta; unsigned int key; // black }; As you can see a color types can be defined very differently. Sometimes a color can even be a mixture of integer and floating point values, see HSV or HSL color space. Now imagine a function that takes any kind of image that's made of of a certain color space. By the way this is not GIL-comlaint code. I'm simplifying for the sake of understanding. template <class IMAGE> void create_histogram( const IMAGE& image ) { typedef IMAGE::color_t color_t; //somehow create type vector and subsequently a tuple containing //the color channel types typedef std::map< color_tuple, unsigned int > histogram_t; histogram_t histogram; for( IMAGE::iterator it = image.begin() ; it != image.end() ; ++it ) { ++histogram[*it]; } } Does that makes sense now? Christian

Christian Henning wrote:
Creating a type vector depending on the template parameter, S, is certainly OK. I'll have to ignore the "bad pseudo code" though ;) You have to do it another way. Tell me precisely what you wish to do and I may be able to provide an example. Actually, I am compiling a small set of simple use-case examples. You wouldn't mind if I use our first example, would you?
No, of course not. How about a real life example? I trying to create a generic histogram operator for GIL ( Generic Image Library - see http://opensource.adobe.com/gil/index.html ).
To create a histogram I need to count all colors of an image and put them into a map. Since there are many different color definitions, like rgb-8bit, cymk32, gray-8bit, etc., I was intend to create the key type of the histogram map as a tuple. For example:
struct rgb8 { static const int num_channels = 3;
unsigned char red; unsigned char green; unsigned char blue;
};
struct cymk32 { static const int num_channels = 4;
unsigned int cyan; unsigned int yellow; unsigned int magenta; unsigned int key; // black };
As you can see a color types can be defined very differently. Sometimes a color can even be a mixture of integer and floating point values, see HSV or HSL color space.
Now imagine a function that takes any kind of image that's made of of a certain color space. By the way this is not GIL-comlaint code. I'm simplifying for the sake of understanding.
template <class IMAGE> void create_histogram( const IMAGE& image ) { typedef IMAGE::color_t color_t;
//somehow create type vector and subsequently a tuple containing //the color channel types
typedef std::map< color_tuple, unsigned int > histogram_t;
histogram_t histogram;
for( IMAGE::iterator it = image.begin() ; it != image.end() ; ++it ) { ++histogram[*it]; } }
Does that makes sense now?
Not sure. Why not simply make IMAGE::color_t the key? Then give std::map a template key compare function templated by color_t; the template can be specialized for each color definition. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Not sure. Why not simply make IMAGE::color_t the key? Then give std::map a template key compare function templated by color_t; the template can be specialized for each color definition.
I suppose that would work, as well. But since I'm lazy ;-) and do not want to create a specialized template for each color defintion, I thought it might be cool to use some metaprogramming magic. Also, GIL is suppose to be extensible for users. Meaning they can define whatever color type they want. It would lessen their learning curve when there is a generic solution for all kinds of colors definitions. Isn't the purpose of metaprogramming to avoid programming that can be done by the compiler? As I said all the information is available at compile time. For example earlier in this thread there is a solution using boost::array. But this one is limited for homogeneous color types. I think you mentioned earlier that there is a solution. I would like to know. It would be very educational to me to see what it's like. Thanks, Christian

Christian Henning wrote:
Not sure. Why not simply make IMAGE::color_t the key? Then give std::map a template key compare function templated by color_t; the template can be specialized for each color definition.
I suppose that would work, as well. But since I'm lazy ;-) and do not want to create a specialized template for each color defintion, I thought it might be cool to use some metaprogramming magic. Also, GIL is suppose to be extensible for users. Meaning they can define whatever color type they want. It would lessen their learning curve when there is a generic solution for all kinds of colors definitions.
Isn't the purpose of metaprogramming to avoid programming that can be done by the compiler? As I said all the information is available at compile time.
For example earlier in this thread there is a solution using boost::array. But this one is limited for homogeneous color types.
I think you mentioned earlier that there is a solution. I would like to know. It would be very educational to me to see what it's like.
Sure! It's interesting to note that Dan and I just recently wrote an article describing such a mapping from arbitrary structs to fusion sequences. The procedure requires a one-time mapping (a few lines of code) for each struct, and, afterwhich, you can use the mapping anywhere you want. In our example, serialization, in yours, histograms. The list is endless because the structs essentially become generic entities. This is such a common need that I am now thinking about ways to make it more seamless. I'll get back to you on this... Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Sure! It's interesting to note that Dan and I just recently wrote an article describing such a mapping from arbitrary structs to fusion sequences. The procedure requires a one-time mapping (a few lines of code) for each struct, and, afterwhich, you can use the mapping anywhere you want. In our example, serialization, in yours, histograms. The list is endless because the structs essentially become generic entities.
This is such a common need that I am now thinking about ways to make it more seamless. I'll get back to you on this...
Looking forward! Is the mentioned article accessible somewhere?
participants (3)
-
Christian Henning
-
Joel de Guzman
-
me22