Fellow boost enthusiasts, I want to be able to store a set of information that contains types. For example:
template<typename T> void register_field( const FieldID id ) { // need to keep a record of (T,id) }
Later on, I need to recover the type and id (T,id) for use. Any thoughts on a way to accomplish this? Thanks for any advice, James
AMDG James Sutherland wrote:
Fellow boost enthusiasts,
I want to be able to store a set of information that contains types. For example:
template<typename T> void register_field( const FieldID id ) { // need to keep a record of (T,id) }
Later on, I need to recover the type and id (T,id) for use. Any thoughts on a way to accomplish this?
Thanks for any advice,
James
How are you using T when you recover it? I assume that std::vector<std::pair<const std::type_info*, FieldID> > doesn't do what you need? If you need to recover T at compile time to do some template instantiations or something, then you can't use an ordinary container because you lose the static type information. If the set of possible types is known up front you can use Boost.Fusion. Otherwise, you can use some kind of type erasure to capture all the information about T that you need. In Christ, Steven Watanabe
Steve, Firstly, on behalf of the many of us who benefit from your helpful suggestions, thank you!
How are you using T when you recover it? I assume that std::vector<std::pair<const std::type_info*, FieldID> > doesn't do what you need?
Your assumption is correct - storing type_info will not work. What I would like to do with the (T,FieldID) pairs is something like: patch->field_manager<T>().create_field( id ); I would want to iterate over all of the (T,id) pairs that were registered. The problem is that the "patch" object is not available when the register_field() method is visited, so this must be a two-stage process.
If you need to recover T at compile time to do some template instantiations or something, then you can't use an ordinary container because you lose the static type information.
If the set of possible types is known up front you can use Boost.Fusion. Otherwise, you can use some kind of type erasure to capture all the information about T that you need.
Unfortunately, I do not know the full set of types, as this is an arbitrarily extensible set. I have had other occasions where I must do similar things and have addressed the issue through a mixture of polymorphism and class templates. For example: class Base{ virtual void common_functionality(); }; template<typename T> class SpecialType : public Base { SpecialType( Patch& patch, FieldID id ) : patch_( patch ), id_( id ) { } void common_functionality() { patch_.field_manager<T>().create_field( id_ ) } ... }; Now one can create something like: typedef std::vector<Base*> mySet; mySet.push_back( new SpecialType<FieldType1>( patch, id1 ) ); mySet.push_back( new SpecialType<FieldType2>( patch, id2 ) ); ... for( std::vector<Base>::iterator i=mySet.begin(); i!=mySet.end(); ++i ) { i->common_functionality(); } This hinges on being able to abstract all functionality into the common_functionality() method, however. Furthermore, it requires instantiation of a SpecialType object. Is this a reasonable workaround, or one that makes generic-programming people cringe? :) James -- James C. Sutherland, Asst. Professor, Dept. of Chemical Engineering The University of Utah 50 S. Central Campus Dr, 3290 MEB Salt Lake City, UT 84112-9203 Tel: (801) 585-1246 http://www.che.utah.edu/~sutherland
AMDG James Sutherland wrote:
I have had other occasions where I must do similar things and have addressed the issue through a mixture of polymorphism and class templates. For example:
class Base{ virtual void common_functionality(); };
template<typename T> class SpecialType : public Base { SpecialType( Patch& patch, FieldID id ) : patch_( patch ), id_( id ) { }
void common_functionality() { patch_.field_manager<T>().create_field( id_ ) } ... };
Now one can create something like:
typedef std::vector<Base*> mySet; mySet.push_back( new SpecialType<FieldType1>( patch, id1 ) ); mySet.push_back( new SpecialType<FieldType2>( patch, id2 ) ); ... for( std::vector<Base>::iterator i=mySet.begin(); i!=mySet.end(); ++i ) { i->common_functionality(); }
This hinges on being able to abstract all functionality into the common_functionality() method, however. Furthermore, it requires instantiation of a SpecialType object.
Is this a reasonable workaround, or one that makes generic-programming people cringe? :)
This is a perfectly reasonable approach. It works and it's the only method that I know of that works. The only issue I see is that it is not exception safe as written. If there is only a single operation, you can use Boost.Function. (Which uses a variation on the same theme internally) template<class T> struct SpecialType { SpecialType(FieldID id) : id_(id) {} void operator(Patch& patch) { patch.field_manager<T>().create_field( id_ ); } FieldID id_; }; std::vector<boost::function<void(Patch&)> > functions; function.push_back(SpecialType<FieldType1>(id)); In Christ, Steven Watanabe
participants (2)
-
James Sutherland
-
Steven Watanabe