Jump to content
  • Advertisement
Sign in to follow this  
zyrolasting

[C++] Passing template-less host class

This topic is 3092 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am rewriting an enumeration library and wish to abandon dynamic binding. In code, I would go from this...
struct Foo
{
virtual int RankA( Type1& ) = 0;
virtual int RankB( Type2& ) = 0;
};
To something like this.
template<class A,class B>
struct Bar
{
  int RankA(Type1& t) { return A::Rank(t); }
  int RankB(Type2& t) { return B::Rank(t); }
};
I want to provide my clients with several preset policies to ease their labor, but one thing stops me: Passing something like Bar above as a parameter to something without having to tack template-templates on it's object or function header. How would I do this, or something like this? boost::any made me think it was remotely possible. I.E.
// not legal, but shows what I'm talking about
void Func(Bar&);

Share this post


Link to post
Share on other sites
Advertisement
boost any uses runtime polymorphism, just very disguised. any is a concrete, non-templated type. It stores run-time type and opaque pointer. When cast, it does run-time check to see if types are convertible, but might use some template magic internally to select proper conversion implementation.

template < class A, class B > 
void func(Bar<A,B> &);

Or, use typedefs.

Or, stick with polymorphism, where the compiler automatically does similar to what any does manually.

Share this post


Link to post
Share on other sites
I don't think it is possible because a class template is not an actual class, until you declare it with template arguments.

So you can't just refer to Bar without template arguments because it is a template not a class. You could give default arguments to the template parameters like this,

template<class A = Foo1,class B = Foo2>
struct Bar
{
....
};

Then you can do:

void Func(Bar<>&);

But of course then you can only pass the default version of Bar to Func.
You could also inherit Bar from some kind of base class and pass a pointer to it into Func but then you have the same kind of problem.

If you want to get polymorphic behavior for Bar but do not want to use virtual functions you might be able to use containers of Bar types, one for each derived version and use polymorphism on the containers instead of on Bar.

Share this post


Link to post
Share on other sites
Quote:
Original post by Antheus
boost any uses runtime polymorphism, just very disguised. any is a concrete, non-templated type. It stores run-time type and opaque pointer. When cast, it does run-time check to see if types are convertible, but might use some template magic internally to select proper conversion implementation.


Just to be clear, it uses a "base" interface that allows for cloning and type info retrieval, and then a templated "holder" class that implements the above interface. Otherwise it wouldn't be possible to assign any's to each other.

As for your actual problem, you can do something very similar. Have a non-templated BarBase interface that is passed to the function as a reference. The actual type that is passed can then be Bar<A, B> or whatever you user wants to use.

Share this post


Link to post
Share on other sites
Quote:
Original post by zyrolasting
I am rewriting an enumeration library and wish to abandon dynamic binding. In code, I would go from this...

*** Source Snippet Removed ***

To something like this.

*** Source Snippet Removed ***

I want to provide my clients with several preset policies to ease their labor, but one thing stops me: Passing something like Bar above as a parameter to something without having to tack template-templates on it's object or function header. How would I do this, or something like this? boost::any made me think it was remotely possible.

I.E.
*** Source Snippet Removed ***


It sounds to me like you want to use template templates. Yes, the word 'template' is supposed to be there twice.


template<class A, class B>
class bar
{
};


template<template<class A, class B> class Param>
class foo
{
Param<int,double> param_one;
Param<string,vector<int> > param_two;
};



Does this solve the problem you're talking about?

Normally you would parameterize something as

template<class A>


which means "the thing that follows can be parameterized with a fully-specified type. But by writing
template<template <class A> class B>
you're saying "the thing that follows can be parameterized with a type that is a template type taking one parameter.

Share this post


Link to post
Share on other sites
I guess I don't totally understand the problem, but would something like this work?
template<class A, class B>
void Func(Bar<A, B>&);
Template argument deduction will take care of any client-side ugliness, if I'm not mistaken.

Share this post


Link to post
Share on other sites
Let me rephrase my problem for those who need clarification.

I want a different feature set per project. Every time I want another set of
features, I have to derive from a filter object and override similar code, which is messy and tedious. I may also have some of the code for what I want written already, but I would have to invoke parent implementations to get it, or copy code from other projects.

All the filter methods can be generalized into policies. Consequently, I need one policy for each method. I would have a huge template argument list!

To use the host class, I pass it to object methods. The problem is, I have to tack template-templates onto the objects I'm passing it to. I don't want to do that. The resulting code would become confusing (picture 10+ template templates following you to every working object of your library). I want to write preset policies that do several enumeration jobs to begin with, and the user can just browse through and build a new filter like a Lego set.

In short, I want to pass a templated host class around and I do NOT want every object I pass it to to be aware it's templated.

Nullsquared had the idea closest to what I was looking for, although I admit I don't fully understand how to implement it. It sounds like a modified Pimpl.

Quote:
As for your actual problem, you can do something very similar. Have a non-templated BarBase interface that is passed to the function as a reference. The actual type that is passed can then be Bar<A, B> or whatever you user wants to use.


[Edited by - zyrolasting on March 4, 2010 6:48:53 AM]

Share this post


Link to post
Share on other sites
He is just saying to implement your own version of boost::any which uses polymorphism internally.
It has an inner class that is non-templated called placeholder. It also has a derived version of this class that is templated called holder which holds an instance of the template type you want to represent, in this case Bar<A,B>. There is a member of type placeholder* that uses polymorphism to cast it's held member to the actual value type at runtime.
So there is no way to avoid virtual functions when you are doing polymorphism unless you reduce the actual amount of times you need to check the type of the object or just use alot of switch statements.

Share this post


Link to post
Share on other sites
Quote:
Original post by zyrolasting
Let me rephrase my problem for those who need clarification.

I want a different feature set per project. Every time I want another set of
features, I have to derive from a filter object and override similar code, which is messy and tedious. I may also have some of the code for what I want written already, but I would have to invoke parent implementations to get it, or copy code from other projects.

All the filter methods can be generalized into policies. Consequently, I need one policy for each method. I would have a huge template argument list!

To use the host class, I pass it to object methods. The problem is, I have to tack template-templates onto the objects I'm passing it to. I don't want to do that. The resulting code would become confusing (picture 10+ template templates following you to every working object of your library). I want to write preset policies that do several enumeration jobs to begin with, and the user can just browse through and build a new filter like a Lego set.

In short, I want to pass a templated host class around and I do NOT want every object I pass it to to be aware it's templated.


I think you're just going to have to use runtime polymorphism then, and you won't be able to completely achieve the semantics you want.

Template templates appear to achieve exactly the semantics you want. If that doesn't work for you, then your clients are going to have accept polymorphic classes at runtime, and additional information about the types they are being passed in so they can get the concrete types out later (e.g. boost::any).

I don't see how template templates are that confusing. Wrap them all in one larger policy class and only pass that policy class around. That policy class doesn't have to be template-templated.

Example:


template<
template<class, class> class LockingPolicy,
template<class,class,class> class DestructionPolicy
>
class policy_simplifier
{
template<class A, class B> struct lock_policy
{
typedef LockingPolicy<A,B>::type type;
};

template<class A, class B, class C> struct destruction_policy
{
typedef DestructionPolicy<A,B,C>::type type;
};
};


template<class A, class B>
struct InsaneLockingPolicy
{
};

template<class A, class B, class C>
struct CrazyDestructionPolicy
{
};


template<class Policy>
void foo()
{
typedef typename Policy::locking_policy<int,double>::type locker;
typedef typename Policy::destruction_policy<string,int>::type destructor;
}

void do_something_with_insane_locking_and_crazy_destruction()
{
typedef policy_simplifier<InsaneLockingPolicy, CrazyDestructionPolicy> policy;

foo<policy>();
}






The important point here is that foo, which is the class USING the policy, is very simple. It doesn't know about template templates.

Share this post


Link to post
Share on other sites
cache_hit, I mentioned that I do not want to use template templates twice now, and you ignored me on both occasions. Thanks, but no thanks. However, I do like that snippet you posted. I'll remember that for future decisions.

If my semantics are impossible, then I'll just toy with what I have to try and get as close to my goal as I can. I appreciate all of the suggestions I have been given, and my thanks go out to all of you.

Back to the drawing board...

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!