Solved

templated templates

Posted on 2009-07-10
34
246 Views
Last Modified: 2012-05-07
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
0
Comment
Question by:Unimatrix_001
  • 15
  • 15
  • 4
34 Comments
 
LVL 12

Expert Comment

by:Let_Me_Be
ID: 24828474
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

0
 
LVL 3

Author Comment

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

template < typename DataType, class Storage >
0
 
LVL 12

Expert Comment

by:Let_Me_Be
ID: 24828488
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 ;-).
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24828498
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>>

?
0
 
LVL 40

Expert Comment

by:evilrix
ID: 24828520
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

0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24828527
Hi Ricky,

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

Thanks,
Uni.
0
 
LVL 40

Expert Comment

by:evilrix
ID: 24828555
>> 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.
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24828572
Could you explain the syntax of:
              >> template <typename> class ThreadPolicy
...perhaps that would help me better understand it...?
0
 
LVL 12

Expert Comment

by:Let_Me_Be
ID: 24828573
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.
0
 
LVL 40

Expert Comment

by:evilrix
ID: 24828574
>> 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.
0
 
LVL 40

Expert Comment

by:evilrix
ID: 24828580
>> 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;
0
 
LVL 40

Expert Comment

by:evilrix
ID: 24828590
>> 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) :)
0
 
LVL 12

Expert Comment

by:Let_Me_Be
ID: 24828606
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.
0
 
LVL 40

Expert Comment

by:evilrix
ID: 24828625
>> 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.
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24828630
Btw, just so you know... reply coming up... :)
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24828669
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.
0
 
LVL 40

Expert Comment

by:evilrix
ID: 24828728
>> 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.
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
LVL 40

Expert Comment

by:evilrix
ID: 24828747

**** 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

0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24828780
Ah I may be getting this... Gonna do a bit of reading with the posts above... :)
0
 
LVL 40

Expert Comment

by:evilrix
ID: 24828796
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.
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24828797
>>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! :)
0
 
LVL 40

Expert Comment

by:evilrix
ID: 24828813
Uri, off to bed now (3:30am UK time). I'll catch up tomorrow.

Night dude.
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24828819
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.
0
 
LVL 40

Expert Comment

by:evilrix
ID: 24828830
>> in the UK as well.
Which Part? Me, Luton (25 miles north of London).
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24830215
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
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24830231
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
0
 
LVL 40

Expert Comment

by:evilrix
ID: 24830392
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 ;)
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24830417
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. ;)
0
 
LVL 40

Accepted Solution

by:
evilrix earned 500 total points
ID: 24833797
Right... I'm back. Yesterday was just too busy for me to get online.

>> then TDataType specifies what data type the container (which is specified with TContainerType) will hold
Well, no. It just specifies the type passed in as the first parameter, that doesn't mean it'll be used to define a concrete type of TContainerClass, which could be defined using any type.

TContainerClass<int> intContainer;
TContainerClass<char> charContainer;

>> The TNullDataType isn't used at all
I never bother to specify the name, it's just a signature and the name isn't required...

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

...just like with a function signature you can leave of the parameter names...

void foo(int i, float f, char c);
void foo(int, float, char);

>> but is required because a vector (and most other containers) are declared as follows:
heh. that's not how vector is defined. Remember my little puzzle I set you and your question about allocators? But, other than that, yes TContainerClass defines a template template parameter that will accept any template defined thus

TContainer< TParam > // This is NOT how a vector is defined, so vector cannot be used here

But this is not going to work for a vector because a vector has a signature of template<typename valueT, typename allocatorT> vector<valueT, allocatorT> (see code below)

>> What I'm not quite grasping is why we must specify the data type for the container twice
You're not, the first type and the template type are unrelated, just because you might use the template type to define a concrete instance of the container doesn't mean you have too. The type parameter TDataType and the template parameter TContainerType are completely 2 different unassociated entities unless you bind them together in a definition to create a concrete type of TContainerType<TDataType>

template < typename TDataType, template < typename > class TContainerType >
void foo()
{
   TContainerType<TDataType> tContainer; // Now we bind them together (but we don't have to)
   TContainerType<int> intContainer;
}

>> Why the need to replace the last typename with class?
Because that's the syntax... you are not declaring a type here you are declaring a template class

Although often used interchangeably, there is a semantic difference between the template class and class template
http://womble.decadentplace.org.uk/c++/template-faq.html#phrase-order

"Q: Is there a difference between a function template and a template function, or between a class template and a template class?

A: The term "function template" refers to a kind of template. The term "template function" is sometimes used to mean the same thing, and sometimes to mean a function instantiated from a function template. This ambiguity is best avoided by using "function template" for the former and something like "function template instance" or "instance of a function template" for the latter. Note that a function template is not a function. The same distinction applies to "class template" versus "template class". "




#include <vector>
 

template < typename DataType, template < typename T, typename A = std::allocator<DataType>  > class Storage >

class SomeClass

{

    Storage<DataType> data;

};
 
 

int main()

{

	SomeClass<int, std::vector> someClass;

}

Open in new window

0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24834410
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?
0
 
LVL 40

Expert Comment

by:evilrix
ID: 24834418
>> 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

0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24834424
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.
0
 
LVL 3

Author Closing Comment

by:Unimatrix_001
ID: 31602329
Thank you.
0
 
LVL 40

Expert Comment

by:evilrix
ID: 24834445
Uri, you are very welcome.
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Unlike C#, C++ doesn't have native support for sealing classes (so they cannot be sub-classed). At the cost of a virtual base class pointer it is possible to implement a pseudo sealing mechanism The trick is to virtually inherit from a base class…
Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now