Link to home
Start Free TrialLog in
Avatar of Unimatrix_001
Unimatrix_001Flag for United Kingdom of Great Britain and Northern Ireland

asked on

templated templates

Hello.

Would somebody mind giving a (very) trivial example of where a templated template would be used and appropriate code? As I'm not seeing the purpose of them.

Thank you,
Uni
Avatar of Let_Me_Be
Let_Me_Be
Flag of United States of America image

For example this. Your class not only allows selecting data type but also the storage type for the data.
template < typename DataType, template < typename > class Storage >
class SomeClass
{
    Storage<DataType> data;
};

Open in new window

Avatar of Unimatrix_001

ASKER

My apologies, I'm afraid I'm not seeing the difference between that and this:

template < typename DataType, class Storage >
The difference is that in your example, you require the user to give you a storage compatible with the data type. You can of course do that. The main problem is what happens when the user presents a storage that is semi-compatible (SomeClass<int,vector<double> >). The code might compile and very, very, very bad things might happen (trust me, dark magic here ;-).
The main problem is what happens when the user presents a storage that is semi-compatible, but couldn't this be done to alleviate the problem:

template<typename Storage>
class SomeClass{
    Storage data;
};
SomeClass<vector<int>>

?
Avatar of evilrix
templated templates are very useful when doing policy driven design. Consider a policy driven shared pointer with threading policies.

template <
	typename ptrT, // The type of pointer
	typename mutexT, // The type of mutex used by the thread policy (could be shared/timed/unique)
	template <typename> class ThreadPolicy // Thead policy (might be single or multi thread)
>
class SharedPointer : ThreadPolicy<mutexT>
{
	// Implementation goes here
};

Open in new window

Hi Ricky,

Hm, sadly I'm not understanding the purpose of that - mainly because I know nothing about threads... :(

Thanks,
Uni.
>> Hm, sadly I'm not understanding the purpose of that - mainly because I know nothing about threads... :(

Ok, well a smart pointer has to be thread safe (in other words it must be protected from 2 threads trying to change it at the same time) and that protection is provided by a mutex (mutual exclusion) object but there are many different types that behave in different ways and have different semantics. Also, they are expensive in terms of performance. By allowing the mutex and the threading policy to be passed seperately we allow the caller to decide if they want a shared mutex (many readers but only 1 writer) or a timed mutex (block for a period of time and if still no access throw an error) or unique (block forever, never give up waiting for exclusive access). Meanwhile, the threading policy will be different depending upon if you know your application uses multipl;e threads or not. If you are using single threads your threading policy will most likely to nothing if it's using multipel threads the policy will implement aggressive mutual exclusion access to critical sections of the shared pointers code. The idea is these related but not bound together policies can be passed in as template param and template template param and they get bound together at the point of instgantiation. This mean, you can have many different smart pointers behaving in different ways to suit your needs all with the use of a simple typedef...

typedef SharedPointer<int, Shared, Multi> SM_SharedPointer;
typedef SharedPointer<int, Unique, S> SS_SharedPointer; // A little pointless maybe?
typedef SharedPointer<int, Timed, Multi> TM_SharedPointer;

It doesn't matter if you don't fully understand the concepts of threading or mutexes. The important thing is it gives you the flexibility to avoid binding things until the point of instantiation so you can implement your template class using policies rather than concrete types.
Could you explain the syntax of:
              >> template <typename> class ThreadPolicy
...perhaps that would help me better understand it...?
The problem of SomeClass<vector<int>> is that SomeClass does not see the int (in case of vector it actually does, using vector<int>::value_type, but STL is very specific in this). In most cases you need to see that int as well.
>> The main problem is what happens when the user presents a storage that is semi-compatible, but couldn't this be done to alleviate the problem:
When writing generic code using templates we use the terms concept and model (something that will be enforceable in C++0X but for now it's a convention). So a concept is something that a template is designed to work with... it's like the interface it expects. A model is something that implements this so it models the concept. If you write a class that allows callers to specify the storage type your class will expect a storage type that models the concept that your class is designed to work with. This is true of all template parameters whether they are template templates or template types.
>> template <typename> class ThreadPolicy
It basically says, this template parameter is a template class, that I have named Thread Policy, that takes 1 template parameter. It can be instantiated like this...

ThreadPolicy<mutext_type> threadPolicy;
>> SomeClass<vector<int>>
Will not work with

template < typename DataType, template < typename > class Storage >
class SomeClass
{
    Storage<DataType> data;
};

...because  template < typename > class Storage does not define a concept modeled by a vector. Kudos to who can tell me why this is (if not I'll tell you) :)
Btw. Unimatrix_001, I think you should read Modern C++ Design by Andrei Alexandrescu. It will push your C++ understanding (and specifically templates) a lot further.
>> read Modern C++ Design by Andrei Alexandrescu
Great book... but I think a little too advanced for Uri (in fact most C++ programmers :) ) right now. I'm thinking C++ Templates by Vandevoorde & Josuttis is a better place to start.
Btw, just so you know... reply coming up... :)
When writing generic code using templates.....they are template templates or template types.
Ooohhh... My head really hurts. :(


The problem of SomeClass<vector<int>> is that SomeClass does not see the int (in case of vector it actually does, using vector<int>::value_type, but STL is very specific in this). In most cases you need to see that int as well.
Right... That's slightly clearer... So consider the following example::

---------------------------------------------------------------------------------
template<typename TContainerType>
class CStorage{
      TContainerType storageArea;
};
CStorage<vector<int>> object;

will work fine, but the problems within the CStorage class is that it is impossible for me to tell:

      a) What container type I'm using.
      b) What data type that container is using.

which is sometimes good to know, is that correct?
---------------------------------------------------------------------------------

---------------------------------------------------------------------------------
template<typename TContainerType, typename TDataType>
class CStorage{
      TContainerType<TDataType> storageArea;
};
CStorage<vector, int> object;

This too will work fine providing:

      1) The container type I pass in is compatible with the TDataType, of which I have no assurance?

Is that correct?
---------------------------------------------------------------------------------


Kudos to who can tell me why this is
I think you can guess who can't tell you why! ;)


I'm afraid I'm still not quite grasping the concept of having a template within a template. :( I'm trying to get to grips with it by working on the principle of handling a container and it's data type.


template < typename DataType, template < typename > class Storage >

I THINK I see the purpose of this, but I'm still struggling with the syntax. :(


I'm thinking C++ Templates by Vandevoorde & Josuttis is a better place to start.
That reminds me, that should have been delivered today after you recommended it to me a couple of days ago! Must follow that up on Monday....


Thank you,
Uni.
>> a) What container type I'm using.
typeid(TContainerType)

>> b) What data type that container is using.
typeid(TContainerType::value_type) // assuming the standard STL concept has been modeled.

>> The container type I pass in is compatible with the TDataType, of which I have no assurance
Sure you do... if it wasn't then the compiler would error -- if it doesn't that's your assurance :)

>> I think you can guess who can't tell you why! ;)
Look at the other question I just answered for you... look at how vector is defined (you already now this) and now look at that template template parameter and see what it expects... see the difference? Go on Uri, I know you'll get this.

>> I'm afraid I'm still not quite grasping the concept of having a template within a template
it's just a way of telling the compiler what template type to used rather than it being hard coded into the class. So, if you have a stack, for example, you could implement it with a list or a vector or a dequeue. Each has pros and cons. Your stack can take the concrete type as one template param (the type you wish to store in the container) and the storage container type as the template template. Of course, this could eb done by just taking one concrete type of the container already defined to take, for example an int, but doing it as 2 separate params gives the user more flexibility. The type bing store and the container being used might not be decided in the same part of the calling code so the decision of which of these two to use might happen at different times.

>> I THINK I see the purpose of this, but I'm still struggling with the syntax. :(
You define a template this...

template <typename T>

You define a template template thus

template < template <typename> class TemplateTemplateName >

It's just a template declaration within another template declaration(except the class keyword follows it with the name you wish to give the template template -- this is arbitrary and up to you just like the name of any template parameter.

>> That reminds me, that should have been delivered today after you recommended it to me a couple of days ago! Must follow that up on Monday...
I used to have 2 copies :) I can also recommend C++ Template Metaprogramming (concepts, tools and techniques from Boost and Beyind) by David Abrahams and Aleksey Gurtovey.

**** Build of configuration Debug for project scratchcpp ****

make -k all
Building file: ../main.cpp
Invoking: GCC C++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"main.d" -MT"main.d" -o"main.o" "../main.cpp"
../main.cpp: In function int main():
../main.cpp:13: error: type/value mismatch at argument 2 in template parameter list for template<class DataType, template<class T> class Storage> class SomeClass
../main.cpp:13: error:   expected a template of type template<class T> class Storage, got template<class _Tp, class _Alloc> class std::vector
../main.cpp:13: error: invalid type in declaration before ; token
../main.cpp:13: warning: unused variable someClass
make: *** [main.o] Error 1
make: Target `all' not remade because of errors.
Build complete for project scratchcpp

#include <vector>
 
template < typename DataType, template < typename T > class Storage >
class SomeClass
{
    Storage<DataType> data;
};
 
 
int main()
{
	SomeClass<int, std::vector> someClass;
}

Open in new window

Ah I may be getting this... Gonna do a bit of reading with the posts above... :)
No worries Uri.

BTW: The reason I'm letting you figure out my little puzzle is because it will aid your understanding if you can figure it out for yourself.
>>The reason I'm letting you figure out my little puzzle is because it will aid your understanding if you can figure it out for yourself.
Thank you. Your help with this is really appreciated! :)
Uri, off to bed now (3:30am UK time). I'll catch up tomorrow.

Night dude.
Hehehe, yep I need to be getting some sleep as well (in the UK as well. ;) Feeling kind of groggy - Let_Me_Be hope you don't mind if I knock off and look at this tomorrow - perhaps a bit of a sleep will help sort things out. :)

Later.
Uni.
>> in the UK as well.
Which Part? Me, Luton (25 miles north of London).
Uurgh... didn't sleep last night - kept thinking about templating templates! :(

>>Which Part?
Newcastle. :)

Anyways, I think I may be a little closer to understanding things... :) So if we've got something like:

     template < typename TDataType, template < typename TNullDataType > class TContainerType >

then TDataType specifies what data type the container (which is specified with TContainerType) will hold. The TNullDataType isn't used at all, but is required because a vector (and most other containers) are declared as follows:

vector<TDataType>

So we need the TNullDataType to satisfy the way containers are declared. What I'm not quite grasping is why we must specify the data type for the container twice, why can't we just use TNullDataType and not have the first parameter (TDataType)?

Thanks,
Uni
Also, not quite grasping why we can't have:

     template < typename TDataType, template < typename TNullDataType > typename TContainerType >

Why the need to replace the last typename with class? I know you (evilrix) mentioned it in passing in a previous question but it was not relevant then for it to be explained why.

Thanks,
Uni
Hey Uri...

Just a quick holding post. I am quite busy today (Saturday's eh?) but I will try and get back to you later.

Meanwhile, here are some links I think might help you out a little...

http://www.informit.com/articles/article.aspx?p=376878
http://www.progdoc.de/papers/ttp/psi-ttp/psi-ttp.html

..I'll try and respond to you fully tonight.

>> Newcastle. :)
Geordie eh? "Shy Bairns Get Nae Sweeties" (apparently that's a Geordie thing to day). Great place to go drinking ;)
Ok cheers. Yeah no problem mate take your time. :) Hehehe, well I'm just outside geordie land, but it's the closest place that anybody really knows. Still got a bit of the accent though. ;)
ASKER CERTIFIED SOLUTION
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi evilrix,

>>Right... I'm back. Yesterday was just too busy for me to get online.
Hehe, not a problem mate. :)

>>...just like with a function signature you can leave of the parameter names...
I'm not quite sure about this part. If we have:

template<typename, typename>
class A{};

how can class A ever use anything within the template as there are no parameter names to associate with?
>> how can class A ever use anything within the template as there are no parameter names to associate with?
If it's not being referenced there is no need to name it. Instantiations still have to conform to that signature though. In the case of a template template parameter we're just telling the compiler the template must conform to that signature but since we're not using the template parameters themselves we don't need to provide them.
template<typename A, typename /* never used so it has no name*/ >
class CMyClass{
       A var1;
 
};
 
int main()
{
	CMyClass<int, float> cif;
}

Open in new window

Ah okay... Well, most of what you've said I've understood and I should be getting the template book you recommended tomorrow so I shall accept one of your many thorough comments! Got to say your patience is second to none! :)

Thanks very much,
Uni.
Thank you.
Uri, you are very welcome.