Click here to Skip to main content
13,835,436 members
Click here to Skip to main content
Add your own
alternative version


32 bookmarked
Posted 7 Dec 2004
Licenced CPOL

Using generics in C++/CLI

Rate this:
Please Sign up or sign in to vote.
Introduces generics and compares it with templates


Beginning with .NET 2.0, Microsoft has introduced generics into the CLI whereby parameterized types can be declared and used. For C# and VB users, this must have been extremely exciting news; but for C++ people who were already used to templates, this might not have sounded all that interesting. You often hear C++ people ask why they need to use generics when they already have templates. [Note - In C++/CLI, templates can be used both with native and with managed types].

Generics and templates, while similar in nature, are also different in many ways. The most outstanding of these differences is that while templates are implemented by the compiler, generics are instantiated at runtime by the CLR's execution engine (this is possible because generics is directly supported by MSIL). For a detailed write-up on how templates and generics differ, see Brandon Bray's blog entry - Templates and Generics.

This article is not intended to demonstrate how generics are cooler than templates (or even the reverse for that matter), rather it just tries to expose the syntactic usage of generics in C++/CLI. I would like to state here that I found generics rather limited when compared to templates, that too despite not being a core-template guy myself.

Basic syntax

Throughout the article, I'll show some code using templates and then show the equivalent code using generics. Here's a typical native class template.

<PRE lang=mc++>template<typename T1, typename T2> class NativeData { public: NativeData(T1 t1) { m_t1 = t1; } void DoStuff(T2 t2) { //... } private: T1 m_t1; };

Now, here's the equivalent in generics :-

<PRE lang=mc++>generic<typename T1, typename T2> ref class GenericData { public: GenericData(T1 t1) { m_t1 = t1; } void DoStuff(T2 t2) { //... } private: T1 m_t1; };

Looks just about identical, except that instead of <CODE lang=mc++>template, the keyword to be used is <CODE lang=mc++>generic. [Note - <CODE lang=mc++>generic is one of the 3 new keywords introduced in C++/CLI, the other two being <CODE lang=mc++>gcnew and <CODE lang=mc++>nullptr. All other keywords are context sensitive keywords like <CODE lang=mc++>ref or spaced keywords like <CODE lang=mc++>for each].


See the following template-based class :-

<PRE lang=mc++>template<typename T> class Native { public: void Start(int x) { T* t = new T(); t->Bark(x); t->WagTail(); delete t; } };

Since templates use lazy constraints, the above code compiles fine (the compiler won't specialize the class template until an instantiation).

And assuming we want to use the class as follows :-

<PRE lang=mc++>Native<NativeDog> d1; d1.Start(100);

We need to have a class <CODE lang=mc++>NativeDog similar to :-

<PRE lang=mc++>class NativeDog { public: void Bark(int Loudness) { Console::WriteLine("NativeDog::Bark {0}",Loudness); } void WagTail() { Console::WriteLine("NativeDog::WagTail"); } };

As long as the class we are specifying as the template type parameter has the <CODE lang=mc++>Bark and <CODE lang=mc++>WagTail methods, it compiles fine. But in generics, we have to specify the constraint (since generics are implemented at runtime). The generic equivalent will be :-

<PRE lang=mc++>interface class IDog { void Bark(int Loudness); void WagTail(); };<PRE lang=mc++>generic<typename T> where T:IDog ref class GenRef { public: void Start(int x) { T t = Activator::CreateInstance<T>(); t->Bark(x); t->WagTail(); delete safe_cast<Object^>(t); } };

Now that we have specified a constraint for the generic parameter, we can invoke methods on it (as allowed by the constraint). If you are wondering why I had to use the generic overload of <CODE lang=mc++>Activator::CreateInstance, it's because the compiler won't allow you to <CODE lang=mc++>gcnew a generic parameter. Similarly, it won't let you <CODE lang=mc++>delete a generic parameter and hence the <CODE lang=mc++>safe_cast to <CODE lang=mc++>Object.

To use the class, we do something like :-

<PRE lang=mc++>ref class Dog : IDog { public: void Bark(int Loudness) { Console::WriteLine("Dog::Bark {0}",Loudness); } void WagTail() { Console::WriteLine("Dog::WagTail"); } };<PRE lang=mc++>GenRef<Dog^> g1; g1.Start(100);

Generic functions

C++/CLI also supports generic functions (you can have a non-generic class with a generic function or you can have a global generic function). For example :-

<PRE lang=mc++>generic<typename T> where T:IDog void DoAll(T t) { t->Bark(0); t->WagTail(); }

Issues with the constraint mechanism

Doing some things are rather more complicated with generics than with templates.

Example 1

See the following template code :

<PRE lang=mc++>template<typename T> void NativeIncrement(T t, int x) { t += x; }

Now, the basic issue with doing this with generics would be that it's difficult to define a constraint that will allow the <CODE lang=mc++>+= operator to work on the generic type parameter. One possible workaround is to define an interface called <CODE lang=mc++>IIncrementable (similar to the generic collection classes using generic interfaces like <CODE lang=mc++>IComparable<T>)

<PRE lang=mc++>interface class IIncrementable { void Add(int); };<PRE lang=mc++>generic<typename T> where T:IIncrementable void RefIncrement(T t, int x) { t->Add(x); }

And we can use it on classes that implement <CODE lang=mc++>IIncrementable :-

<PRE lang=mc++>ref class MyInt : IIncrementable { public: MyInt(int n) : m_num(n){} void Add(int x) { m_num += x; } private: int m_num; };

We still cannot use the generic function <CODE lang=mc++>RefIncrement with simple types like <CODE lang=mc++>int, <CODE lang=mc++>float etc. For that, we can use a work-around suggested by Jambo (discussed later in this article).

Example 2

See the following function template :-

<PRE lang=mc++>template<typename T> T NativeAdd(T t1, T t2) { return t1 + t2; }

As above, since there is no .NET interface called <CODE lang=mc++>IAddable, we have to work around the situation. Instead of using an interface like we did last time, we'll use a <CODE lang=mc++>ref class as constraint - so we can define a CLI-compatible binary <CODE lang=mc++>+ operator.

<PRE lang=mc++>ref class A1 { public: A1(int x):m_x(x){} static A1^ operator +(const A1^ a1,const A1^ a2) { return gcnew A1(a1->m_x + a2->m_x); } int m_x; };<PRE lang=mc++>generic<typename T> where T:A1 T GenericAdd(T t1, T t2) { A1^ tmp = gcnew A1(t1->m_x + t2->m_x); return static_cast<T>(tmp); }

And yeah, all that ugly casting is necessary. Again this generic function will not work on simple types like <CODE lang=mc++>int, <CODE lang=mc++>float etc.

Work-around for simple types

Jambo calls this the Adapter Pattern [but neither of us are really sure whether that's what this should be called]. Basically we have a singleton class, <CODE lang=mc++>NumericalAdapter and a generic interface, <CODE lang=mc++>INumericalOperations with <CODE lang=mc++>Add and <CODE lang=mc++>Subtract methods. The <CODE lang=mc++>NumericalAdapter class has inner classes, one for each type like <CODE lang=mc++>IntNumericalAdapter, <CODE lang=mc++>FloatNumericalAdapter etc. and also provides a static generic method <CODE lang=mc++>GetNumericalAdapter which returns a <CODE lang=mc++>INumericalOperations<T> object.

<PRE lang=mc++>generic<typename T> interface class INumericalOperations { T Add( T t1, T t2 ); T Subtract( T t1, T t2 ); };<PRE lang=mc++>ref class NumericalAdapter { private: static NumericalAdapter^ m_NumericalAdapter; NumericalAdapter(){}; public: static NumericalAdapter() { m_NumericalAdapter = gcnew NumericalAdapter(); } private: ref class IntNumericalAdapter : INumericalOperations<int> { public: int Add( int t1, int t2 ) { return t1 + t2; } int Subtract ( int t1, int t2 ) { return t1 - t2; } }; ref class FloatNumericalAdapter : INumericalOperations<float> { public: float Add( float t1, float t2 ) { return t1 + t2; } float Subtract ( float t1, float t2 ) { return t1 - t2; } }; public: generic<typename T> static INumericalOperations<T>^ GetNumericalAdapter() { Type^ typ = T::typeid; if( typ == int::typeid) { return dynamic_cast<INumericalOperations<T>^>(gcnew IntNumericalAdapter()); } if( typ == float::typeid) { return dynamic_cast<INumericalOperations<T>^>(gcnew FloatNumericalAdapter()); } return nullptr; } };

And we use the class as follows :-

<PRE lang=mc++>int i1 = 7, i2 = 23; int i3 = NumericalAdapter::GetNumericalAdapter<int>()->Add(i1, i2); float f1 = 5.67f, f2 = 7.13f; float f3 = NumericalAdapter::GetNumericalAdapter<float>()->Add(f1, f2); <P lang=mc++>Pretty cool, huh? They don't call Jambo Mister DotNet for nothing.


Generics are not as powerful or flexible as templates are (the intentions behind generics were probably different from that for templates), but if you want your code to be compatible with other CLI languages like C# or VB.NET, you'd be much better off using generics instead of templates wherever possible. Generics can also be used to write generic wrappers over existing C++ template libraries so as to expose them to the rest of the .NET world. As usual, please feel free to submit your criticisms, suggestions and other feedback.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Authors

Nish Nishant
United States United States
Nish Nishant is a Principal Software Architect based out of Columbus, Ohio. He has over 17 years of software industry experience in various roles including Lead Software Architect, Principal Software Engineer, and Product Manager. Nish was a Microsoft Visual C++ MVP between 2002 and 2015.

Nish is an industry acknowledged expert in the Microsoft technology stack. He authored C++/CLI in Action for Manning Publications in 2005, and had previously co-authored Extending MFC Applications with the .NET Framework for Addison Wesley in 2003. In addition, he has over 140 published technology articles on and another 250+ blog articles on his WordPress blog. Nish is vastly experienced in team management, mentoring teams, and directing all stages of software development.

Contact Nish : If you are interested in hiring Nish as a consultant, you can reach him via his google email id voidnish.

Company Website :

James T. Johnson
Software Developer (Senior) InfoPlanIT, LLC
United States United States
James has been programming in C/C++ since 1998, and grew fond of databases in 1999. His latest interest has been in C# and .NET where he has been having fun writing code starting when .NET v1.0 was in its first beta.

He is currently a senior developer and consultant for InfoPlanIT, a small international consulting company that focuses on custom solutions and business intelligence applications.

He was previously employed by ComponentOne where he was a Product Manager for the ActiveReports, Data Dynamics Reports, and ActiveAnalysis products.

Code contained in articles where he is the sole author is licensed via the new BSD license.

You may also be interested in...


Comments and Discussions

GeneralNoob Troubles Pin
Draken Nuwar14-Oct-06 9:00
memberDraken Nuwar14-Oct-06 9:00 
GeneralRe: Noob Troubles Pin
Bartosz Bien4-Feb-07 22:01
memberBartosz Bien4-Feb-07 22:01 
GeneralNice Article Pin
Holger Grund1-Feb-05 6:37
memberHolger Grund1-Feb-05 6:37 
GeneralC++ developers choose Pin
Majid Shahabfar9-Dec-04 0:07
memberMajid Shahabfar9-Dec-04 0:07 
GeneralRe: C++ developers choose Pin
Arno Nimoy9-Dec-04 11:31
sussArno Nimoy9-Dec-04 11:31 
GeneralRe: C++ developers choose Pin
Nemanja Trifunovic10-Dec-04 10:46
memberNemanja Trifunovic10-Dec-04 10:46 
GeneralRe: C++ developers choose Pin
Nemanja Trifunovic10-Dec-04 10:37
memberNemanja Trifunovic10-Dec-04 10:37 
QuestionSurely that's not all?? Pin
Don Clugston8-Dec-04 19:26
memberDon Clugston8-Dec-04 19:26 
AnswerRe: Surely that's not all?? Pin
Nish Nishant8-Dec-04 19:37
sitebuilderNish Nishant8-Dec-04 19:37 
Generalsecond example Pin
Goran Mitrovic7-Dec-04 22:25
memberGoran Mitrovic7-Dec-04 22:25 
GeneralRe: second example Pin
Nish Nishant7-Dec-04 22:34
sitebuilderNish Nishant7-Dec-04 22:34 
GeneralRe: second example Pin
Holger Grund1-Feb-05 6:14
memberHolger Grund1-Feb-05 6:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web05 | 2.8.190114.1 | Last Updated 8 Dec 2004
Article Copyright 2004 by Nish Nishant, James T. Johnson
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid