Upload
penelope-donat
View
226
Download
5
Embed Size (px)
Citation preview
DEV 321Understanding and Using Advanced C++ Template Features and Topics on ISO C++
Scott CurrieProgram ManagerVisual C++Microsoft Corporation
[After saying good things about VC++, which prompted chuckles from the audience]
"I may complain about Microsoft’s [C++] standards conformance, but it’s a good
compiler. If you can get your code through the front end, the back end will generate
amazingly efficient executables."
-- Scott Meyers, Boston, March 2002
A word from the field about standards conformance
[After saying good things about VC++, which prompted chuckles from the audience]
"I may complain about Microsoft’s [C++] standards conformance, but it’s a good
compiler. If you can get your code through the front end, the back end will generate
amazingly efficient executables."
-- Scott Meyers, Boston, March 2002
A word from the field about standards conformance
AgendaWhy you should care about conformanceA look at particular conformance areas:
Member templates(standard "iterator-range" constructors)Partial template specialization(specializing std::vector; Loki::TypeList)Koenig lookup (a.k.a. argument-dependent lookup, ADL)
SummaryWhere to find out moreQ & A
AgendaWhy you should care about conformanceA look at particular conformance areas:
Member templates(standard "iterator-range" constructors)Partial template specialization (specializing std::vector; Loki::TypeList)Koenig lookup (a.k.a. argument-dependent lookup, ADL)
SummaryWhere to find out moreQ & A
Why you should care about conformance
Library writersUse it daily for PTS and other features
The rest of usCan use some techniques directly
Library consumption has to work
Anyone who uses multiple compilersEasier porting across compilers
Lower maintenance and fewer #ifdefs
AgendaWhy you should care about conformanceA look at particular conformance areas:
Member templates(standard "iterator-range" constructors)Partial template specialization (specializing std::vector; Loki::TypeList)Koenig lookup (a.k.a. argument-dependent lookup, ADL)
SummaryWhere to find out moreQ & A
A look into the standard libraryThe standard library provides some useful containers:
std::vector<int> v; // safer than C-style array// safer than C-style arraystd::list<SomeUserType> l;// much more flexible, too// much more flexible, toostd::deque<bool> d; // pick a data structure…// pick a data structure…
You can construct a container in many ways…vector<int> v1; // empty by default// empty by defaultvector<int> v2( 10 ); // 10 ints with value 0// 10 ints with value 0vector<int> v3( 10, 42 ); // 10 ints with value 42// 10 ints with value 42vector<int> v4( v1 ); // make a copy of v1// make a copy of v1
…but not from another container?list<int> l; // a list of ints// a list of intsvector<int> v5( l ); // error – but isn’t this a// error – but isn’t this a
// reasonable thing to // reasonable thing to do?do?
Constructing from an iterator rangeTo make this possible, the standard library containers can all be constructed also from an iterator range:
list<int> l; // a list of ints// a list of intsvector<int> v5( l.begin(), l.end() ); // ok – aha!// ok – aha!
Pointers are iterators too, so construct from an array…
int a[] = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 8 };vector<int> v6( a, a+14 );
// or, strictly: &a[0], &a[ sizeof(a)/sizeof(int) ]// or, strictly: &a[0], &a[ sizeof(a)/sizeof(int) ]… or even from the console using istream_iterators:
vector<string> v( istream_iterator<string>( cin ), (istream_iterator<string>()) );
sort( v.begin(), v.end() );copy( v.begin(), v.end(),
ostream_iterator<string> out( cout, " " ) );
There are infinitely many possible iterator types, so construction from an iterator range must be a member template to work with them all:namespace std { template <class T, class Allocator = allocator<T> > class vector { template <class InputIterator> vector( InputIterator first, InputIterator last /*...*//*...*/ );
// ... much more stuff ...// ... much more stuff ... };}
Constructor templates
Of course, there’s more to member template functions than just constructors
Templated assignment operatorsTemplated accessor functionsTemplated conversionsetc.
Member templates now all work correctly in VC++ 2003These examples all worked in VC++ 2002 tooVC++ 6.0 could not reliably handle any of this
VC++ and member templates
Limitations of member templates
Keep an eye open for a tie-back slide in the Partial Template Specialization section
A member function template shall not be virtual (14.5.2, p3)
Virtual dispatch does not allow compiler to do the right thing statically
So, the compiler emits a table of pointers for virtual members of each derived type (VTable)
This would cause VTable explosion with a single compiland
Impossible with multiple compilands unless a smart linker got involved
AgendaWhy you should care about conformanceA look at particular conformance areas:
Member templates (standard "iterator-range" constructors)Partial template specialization (specializing std::vector; Loki::TypeList)Koenig lookup (a.k.a. argument-dependent lookup, ADL)
SummaryWhere to find out moreQ & A
Here’s that fundamental tool again:namespace std { template <class T, class Allocator = allocator<T> > class vector { /* ... lots of stuff ... *//* ... lots of stuff ... */ };}
You can specialize vector for your own types:
class MyType { /* ... *//* ... */ };namespace std { template<> // explicit specialization// explicit specialization class vector<MyType> // for T == MyType// for T == MyType { /* … lots of stuff … *//* … lots of stuff … */ };}
Note: The above is a complete specialization (we know exactly what all the template arguments are)
A look at std::vector
But what if your type is itself also a template?template<class T> class MyType { /* ... *//* ... */ };namespace std { template<> // explicit specialization???// explicit specialization??? class vector<???> // for T == ???// for T == ??? { /* … lots of stuff … *//* … lots of stuff … */ };}We couldn’t possibly write out all the complete specializations (even if we wanted to)Instead, we want a “partial” specialization – one that is still parameterized, but for a subset of types:namespace std { template<class T>// partial specialization// partial specialization class vector<MyType<T> > // for MyType<T>// for MyType<T> { /* … lots of stuff … *//* … lots of stuff … */ };}
Why partial template specialization
Digression: Boost and LokiBoost
Many excellent template libraries that work well with standard libraryStarted by members of C++ Standards Committee Library Working GroupFree, open source, peer reviewedhttp://www.boost.org/
Loki“A C++ library of designs, containing flexible implementations of common design patterns and idioms”Read Modern C++ Designhttp://sourceforge.net/projects/loki-lib/
Digression: auto_ptrBe careful with std::auto_ptr
Do not point auto_ptr at an arrayIt only deletes. No delete[]
Do not put an auto_ptr in a vectorCan’t be indexed in a standard way
Remember, auto_ptr uses single ownership
Use Boost smart pointers insteadshared_ptr
Performs reference counting
Using a shared_ptr to hold the results of every new will nearly eliminate the possibility of memory leaks
Here’s a fundamental tool from Loki, a list of types:template <class T, class U>struct Typelist { typedef T Head; typedef U Tail;};
Sample usage (simplified by macros ):TYPELIST_1(int)
// Typelist<int, NullType>// Typelist<int, NullType>TYPELIST_2(int, double)
// Typelist<int, Typelist<double, NullType> >// Typelist<int, Typelist<double, NullType> >
// etc.// etc.
A look at Loki::Typelist
Calculate the length of a typelist:template <class TList> struct Length;
template <> struct Length<NullType> { enum { value = 0 };};
template <class T, class U> // partial specializ.// partial specializ.struct Length< Typelist<T, U> > { enum { value = 1 + Length<U>::value };};
Sample usage:
Length< TYPELIST_3(int, double, bool) >::value // 3// 3
(Remember, this is all being done at compile time!)
Why partial template specialization
Why partial template specialization
Select the Nth type of a typelist:template <class TList, unsigned index> struct TypeAt;
template <class Head, class Tail> // partial specializ.// partial specializ.struct TypeAt<Typelist<Head, Tail>, 0> { typedef Head Result;};
template <class Head, class Tail, unsigned int i> // again// againstruct TypeAt<Typelist<Head, Tail>, i> { typedef typename TypeAt<Tail, i - 1>::Result Result;};
Sample usage:TypeAt< TYPELIST_3(int, double, bool), 1>::Result
// double// double
Other operations on typelists:Search: IndexOf<>Append: Append<>Erase: Erase<>Remove duplicates: NoDuplicates<>Replace: Replace<>Partial sort according to an inheritance hierarchy (really!): DerivedToFront<>
Every single one of these requires partial specialization (or "partial workarounds") because they’re defined recursively with a special case (or two) to end the recursion
Why partial template specialization
Something more obviously(?) useful (& with TTPs!):template <class TList, template <class> class Unit>class GenScatterHierarchy;template <class T1, class T2, template<class> class Unit>class GenScatterHierarchy<Typelist<T1, T2>, Unit> : public GenScatterHierarchy<T1, Unit> , public GenScatterHierarchy<T2, Unit> { /*…*/ /*…*/ };template <class AtomicType, template <class> class Unit>class GenScatterHierarchy : public Unit<AtomicType> { /*…*//*…*/ };template <template <class> class Unit>class GenScatterHierarchy<NullType, Unit> { /*…*//*…*/ };
This lets a class inherit from every type in a flexible list of types.
Generics + OO = a boatload of power
Member Templates
Here is the tie-back
Cannot be partially specialized
Only explicit specialization
How do we achieve similar functionality?Overloading
Provides very similar pattern matching
Code bloat
Remember, this is all "executed" at compile time!
To quote Herb Sutter, about Modern C++ Design:
"… ‘can compiler XYZ compile Loki?’ is becoming something of an unofficial benchmark in compiler-writer circles. … Loki is written entirely in normal standard-conforming C++ — only more standard and more conforming, it turns out, than some compilers are yet quite ready to digest. Loki … uses templates so widely and heavily that it tears the tar and stresses the stuffing out of some current compilers. In fact, at the time the book was released [2001], no commercially available compiler could compile all of Loki correctly…"
A word about compiler-busting
PTS Summary
Bread and butter of advanced library writerProvide basis of compile-time programmingTwo types of PTS
Template template parameterSpecify subset of multiple template parameters
Not available for member templatesThey work in Visual C++ .NET 2003You should use to specialize library types for your own types and templated typesRead Modern C++ Design!
AgendaWhy you should care about conformanceA look at particular conformance areas:
Member templates (standard "iterator-range" constructors)Partial template specialization (specializing std::vector; Loki::TypeList)Koenig lookup (a.k.a. argument-dependent lookup, ADL)
SummaryWhere to find out moreQ & A
And now for a word from our standard…namespace NS{ class T { }; void f(T);}
NS::T parm;
int main() { f(parm); // no function f() seems to be in// no function f() seems to be in} // scope -- is all lost?// scope -- is all lost?
A motivating example
And now for a word from our standard…namespace NS{ class T { }; void f(T);}
NS::T parm;
int main() { f(parm); // OK: calls NS::f()// OK: calls NS::f()}
The parameter comes from namespace NS, therefore in addition to looking for candidate functions/functors in all the usual places, the compiler is required to also look in NS
A motivating example
Q: Is this purely a notational convenience? What’s so hard about writing "NS::f(parm);" or "using NS::f;"?
#include <iostream>#include <string> // gives std::operator<<() for // gives std::operator<<() for stringsstringsint main() { std::string hello = "Hello, world"; std::operator<<( std::cout, hello ); // ugh// ugh // "std::cout << hello;" is what we really want // "std::cout << hello;" is what we really want}
It would be disgraceful if the programmer had to qualify this name, because either the operator couldn’t be used naturally, or the user would have to write "using std::operator<<;" (tedious) or "using namespace std;" (although I recommend the latter for other reasons…)
How important is it really?
But VC++ (.NET) 2002 did Koenig lookup only for operators
Happens to be a very common case
Happens to speak directly to the foregoing example
VC++ 2003 does Koenig lookup for all functions, as required by the standard
Useful example of what VC++ 2003 buys you?
Actually, you have it in VC++ .NET
Reimplementing std::swapBasics
namespace NS { swap(tuple x, tuple y) {…} tuple<int,int> x; tuple<int,int> y; … swap(x,y); // OK: calls NS::swap()// OK: calls NS::swap()}
What if swap is out of namespace?namespace NS { swap(tuple x, tuple y) {…}}tuple<int,int> x;tuple<int,int> y;….swap(x,y); // BAD: calls std::swap()// BAD: calls std::swap()NS::swap(x,y); // OK: calls NS::swap(), but annoying// OK: calls NS::swap(), but annoying
More std::swapWhat if now we want a generic method?
namespace NS { swap(tuple x, tuple y) {…}}tuple<int,int> x;tuple<int,int> y;
template <class T>void swap_helper(T source, T target) { …. swap(source, target); // Need Koenig lookup// Need Koenig lookup ….}swap_helper <tuple <int,int> > (x,y);
Koenig Summary
Argument Dependent Lookup
Be aware of operator example
Understand what Koenig Lookup is all aboutGetting around the lack of namespace passing ability to generic code
If you use namespaces, be careful about name collisions and the ordering behavior
If you use namespaces and generics, you will likely have to depend on this
AgendaWhy you should care about conformanceA look at particular conformance areas:
Member templates (standard "iterator-range" constructors)Partial template specialization (specializing std::vector; Loki::TypeList)Koenig lookup (a.k.a. argument-dependent lookup, ADL)
SummaryWhere to find out moreQ & A
Best practices (on any good compiler)
Know your community and the community libraries:
full STL (see also Effective STL)Standard gets revised, so stay up to date
Boost (see www.boost.org)
Loki (see www.moderncppdesign.com)
etc.
Know your power tools:partial specialization (see also Modern C++ Design)
Koenig lookup (see also Exceptional C++)
member template functions
VC++ and you(r projects)
You now have one of the most standards-conforming implementations of one of the most powerful and flexible programming languages in the world
Use Standard C++ to your best advantage:"Explore, try, perform"
Don’t be afraid of making full use of advanced language features
Don’t be afraid of exploring and exploiting the full power of community libraries like Boost and Loki and MTL
Further ReadingA. Alexandrescu. Modern C++ Design(Addison-Wesley, 2001)
The official documentation for the Loki library. See also www.mcppdesign.com and my review of this book at:
"Review of Modern C++ Design"(C/C++ Users Journal, 20(4), April 2002),www.gotw.ca/publications/mcd_review.htm
N. Josuttis. The C++ Standard Library (Addison-Wesley, 1999)
S. Meyers. Effective STL (Addison-Wesley, 2002)H. Sutter. Exceptional C++ and
More Exceptional C++ (Addison-Wesley, 2000 & 2002)
H. Sutter. Guru of the Week (www.gotw.ca)
Community Resources
MS Community Siteshttp://msdn.microsoft.com/visualchttp://gotdotnet.com/team/cplusplus
List of newsgroupshttp://msdn.microsoft.com/newsgroups(Visual Tools and Languages -> C/C++)
Attend a free chat or webcasthttp://microsoft.com/communities/chats/default.mspxhttp://microsoft.com/usa/webcasts/default.asp
C++ User Groups and Forumshttp://www.mvps.org/vcfaqhttp://cplus.about.com/cs/visualchttp://www.accu.orghttp://www.codeguru.comhttp://www.codeproject.comhttp://www.devx.com/cplus/Door/7042
evaluationsevaluations
AgendaWhy you should care about conformanceA look at particular conformance areas:
Member templates (standard "iterator-range" constructors)Partial template specialization (specializing std::vector; Loki::TypeList)Koenig lookup (a.k.a. argument-dependent lookup, ADL)
SummaryWhere to find out moreQ & A
© 2003 Microsoft Corporation. All rights reserved.© 2003 Microsoft Corporation. All rights reserved.This presentation is for informational purposes only. MICROSOFT MAKES NO WARRANTIES, EXPRESS OR IMPLIED, IN THIS SUMMARY.This presentation is for informational purposes only. MICROSOFT MAKES NO WARRANTIES, EXPRESS OR IMPLIED, IN THIS SUMMARY.