Sign in to follow this  
zyrolasting

[C++] Passing template-less host class

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
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
Quote:
Original post by zyrolasting
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.


Basically, something like this:

// declare an interface for bar's
struct barBase
{
virtual void policy1() = 0;
virtual void policy2() = 0;
// etc.
};

void doStuff(barBase &b)
{
b.policy1();
}

// a specific type of bar
template<typename A, typename B>
struct bar: barBase
{
// implement the functions
};

doStuff(bar<int, int>()); // call doStuff with a specific type of bar


If you need the return types to be different between barBase and a class that implements barBase, look into covariant return types: http://en.wikipedia.org/wiki/Covariant_return_type

If you need the parameter types to be different between barBase and a class that implements barBase, you can either use void* or boost::any as the parameters, since you'll know what you have to cast to inside the class that implements barBase. I personally suggest using boost::any since it retains type info over void*, but if you're mostly using pointers and wish to avoid boost::any, then void* is fine.

Share this post


Link to post
Share on other sites
Quote:
Original post by zyrolasting
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...


First of all, your original post says "I wish to abandon dynamic binding". Ok, so you need static binding then. In C++ that is called "templates". Then, you gave an example specifically using templates that looks like something you want but isn't quite there. Well like it or not, template-templates are the only solution. Me mentioning that doesn't mean I'm ignoring you, it means I'm telling you that it's the only solution, and you should either find a way to make it fit in what you need, or bend a little on your requirements.

I could have posted alternate solutions that used dynamic binding that looked different, but I took "I wish to abandon dynamic binding" at face value. If you don't mind having your system dependent on dynamic binding, even if the interface to such dynamic binding is simplified somewhat, then I might have come up with a different answer.

Secondly, I did not ignore you, I responded very specifically to the reason you claimed you don't want to use them, and I provided a precise solution to that problem.

Quote:

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 proposed a direct solution to that EXACT problem so that you can simplify the issue of passing template templates everywhere to the point where it's not confusing. If you still don't want to use them then you're more than welcome to settle for a solution that doesn't really fit your needs. Unless you actually don't mind using dynamic binding after all, in which case you can probably find a wealth of satisfactory solutions.

Share this post


Link to post
Share on other sites
@cache_hit

Please don't steer us into one of "those threads". Once an argument starts here, we'll never get back on track. The bottom line is that I'm inexperienced in generic programming, and writing an essay to validate your solution that I already knew of and did not want to use does not move anything forward. Besides, if what you had really solved my problem, I wouldn't be defending myself right now. I accept I used "dynamic binding" in a contradictory manner. Sorry, now can we please drop this?

Quote:
Considering how vague his question is, I doubt it's the only solution.


Sorry about that. What part of my question is most vague?

Share this post


Link to post
Share on other sites
Quote:
Original post by zyrolasting
Sorry about that. What part of my question is most vague?


The policies part; I don't quite understand how you use them (perhaps this is an issue on my part). Maybe a small code example?

Based on the code example you gave in your OP, my idea should work; did you take a look at it?

Share this post


Link to post
Share on other sites
So zyrolasting, it looks like you just want to declare Func with an argument that needs no template arguments, not abandon dynamic binding completely. In that case, nullSquared has the best solution it seems to me. Or just use boost::any.

Share this post


Link to post
Share on other sites
Quote:
The policies part; I don't quite understand how you use them (perhaps this is an issue on my part). Maybe a small code example?


Sure, here is the simplest pseudo-code doppelganger to my actual project I can think of. Read the comments for tidbits.

/*
NOTE: This is contextual!!
I want to write a whole SLEW of
stuff like this the user can select from
to build an enumeration object easily.
*/

struct FormatRanker
{
static int Rank( const Format& f )
{
// Accept 32 bit format.
return ( f.GetBitCount() == 32 );
}
};

/*
This holds accepted features.
One policy is needed here that exposes
a Rank() method that returns int and accepts
a const reference of type T. (See above)
*/


template <class T, class RankPolicy>
class container
{
storage mStorage;
public:

bool Add( const T& feat )
{
if ( RankPolicy::Rank(feat) < 0 )
{
// Reject
return false;
}

// Accept
mStorage.Add(feat);
return true;
}
};

// This collects core information.
template<class RankDisplayPolicy>
struct HiEnumerator
{
container<Display,RankDisplayPolicy> m_Container;
Enumerate()
{
while ( !DoneEnumeratingDisplays() )
{
Display = GetNextSupportedDisplay();
m_Container.Add(Display);
}
}
};

/*
The below enumerator needs information
from the above one.

This needs to know the template arguments
of HiEnumerator, but it won't use them.

Which brings us back to: How can I remove the below
template argument list and still be aware of HiEnumerator?
*/

template<class DisplayPolicy>
struct LoEnumerator
{
Enumerate( HiEnumerator<DisplayPolicy>& )
{
// Get enumerated info from HiEnumerator,
// But don't care about it's policies.
}
};


I felt nullsquared was on the right track because I needed to separate interface from implementation, but templates are indeed in the mix.

I certainly could use template templates, but I am enumerating Direct3D9 here... The actual template argument list is staggering. The code would be very difficult to read and maintain on my end. If I indeed had only one template argument to worry about and little to collect, I would never have started this thread.

Quote:
Based on the code example you gave in your OP, my idea should work; did you take a look at it?


I'm actually thinking about it right now. Nothing is set in stone yet, though.

Hopefully the above cleared up any confusion.

Share this post


Link to post
Share on other sites
If the project is not confidential, would it be possible to instead describe what the result is supposed to be, or what the user will do?

The best I can guess:
- Enumerate D3D display modes
- Allow user (end user? developer? via config file?) filter that list for some purpose?

Because I do not know what templates have to do with any of this, or what actually needs to be a templated type, and what is concrete.

Long time ago I wrote a display filtering class which used EnumDisplaySettings to put all modes into vector<DEVMODE> (DEVMODE is plain C struct). Then I'd just iterate over that in a for loop. Generic version would be something like:
bool predicate(DEVMODE & dm); // whatever filter to apply

template < class Pred >
void visit(std::vector<DEVMODE> & in, std::vector<DEVMODE> &out, Pred p) {
out.clear();
for (int i = 0; i < in.size(); i++) {
if (p(in[i])) out.add(in[i]));
}
}


To combine multiple filters, one could just call this sequentially:

visit(a, b, ByResolution); a=b; b.clear();
visit(a, b, ByDepth); a=b; b.clear();
visit(a, b, ByFoo);
// b contains the result


Share this post


Link to post
Share on other sites
My objects try to enumerate everything. The user may rank each feature found to be supported, or reject it altogether. This may need to be done once each project, so code may get very repetitious if I used virtual methods. They would be much easier than what I'm doing here, but I feel the use of policies play an important role in reducing that repetition and easing maintenance as a user.

Once the dust settles I would end up with a single run-of-the-mill host class that wraps all aforementioned logic I've shared above and expose a single long template parameter list. The only templated types are policies that rank an enumerated feature. This is why the large collection of pre-written policies was so appealing to me. Everything else should be concrete. I still wanted to compartmentalize the wrapped code and reduce the need of knowing about templates that aren't used, hence the thread...

The end result code might look something like:

typedef IDXEnum<
DispModePolicy_43_169_Aspect, // Only accept 4:3 and 16:9 display modes
FormatPolicy_32BitOnly, // 32 bit adapter formats
FormatPolicy_32BitOnly, // 32 bit back buffer formats
FormatPolicy_DepthAndStencil, // Need depth and stencil bits
CapsPolicy_HTNL_Shader_3 // HW T&L, vertex/pixel shader 3.0 required
...
> MyEnum;


// Usage: D3D is an IDirect3D9*
MyEnum e(D3D);

// Use methods to create device with enumerated data, etc...

Share this post


Link to post
Share on other sites
While your requirements may seem somewhat clear now, are you quite certain that you will never need to use values only available at runtime as parameters? What if eventually you decide "well now it would be nice if i do different things depending on some config file, or the capabilities of the hardware, etc"

Share this post


Link to post
Share on other sites
I shouldn't need to worry about that yet. I allow my library to think it does not know a darn thing about the host PC, and it should try to find every bit of info it can. I did not plan a config file yet, but it should not be too difficult to make use of one later down the road.

The policies I've mentioned merely allow the user to decide what features they want and how much they want them. Everything else is merely collecting information, and is not much different from your typical D3D9 enum library.

God, I wish I came out with that earlier.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this