+ All Categories
Home > Documents > C++ Training Datascope Lawrence D’Antonio

C++ Training Datascope Lawrence D’Antonio

Date post: 17-Jan-2016
Category:
Upload: tieve
View: 27 times
Download: 0 times
Share this document with a friend
Description:
C++ Training Datascope Lawrence D’Antonio. Lecture 7 An Overview of C++: What is Polymorphism? – Parametric Polymorphism. What is polymorphism?. Parametric. Universal. Subtype. Polymorphism. Overloading. Ad-hoc. Coercion. - PowerPoint PPT Presentation
Popular Tags:
137
C++ Training C++ Training Datascope Datascope Lawrence D’Antonio Lawrence D’Antonio Lecture 7 Lecture 7 An Overview of C++: An Overview of C++: What is Polymorphism? – What is Polymorphism? – Parametric Polymorphism Parametric Polymorphism
Transcript
Page 1: C++ Training Datascope Lawrence D’Antonio

C++ TrainingC++ TrainingDatascopeDatascope

Lawrence D’AntonioLawrence D’AntonioLecture 7Lecture 7

An Overview of C++:An Overview of C++:What is Polymorphism? – What is Polymorphism? – Parametric PolymorphismParametric Polymorphism

Page 2: C++ Training Datascope Lawrence D’Antonio

What is polymorphism?What is polymorphism?

Different types of objects respond to the Different types of objects respond to the same message and use the appropriate same message and use the appropriate method.method.

Polymorphism

Universal

Ad-hoc

Parametric

Subtype

Overloading

Coercion

Page 3: C++ Training Datascope Lawrence D’Antonio

Parametric Polymorphism

Parametric polymorphism parametrizes Parametric polymorphism parametrizes the object type (e.g., a list class, where the the object type (e.g., a list class, where the type of object stored is parametrized).type of object stored is parametrized).

Parametric polymorphism in C++ is Parametric polymorphism in C++ is implemented as templates.implemented as templates.

Both classes and functions may be Both classes and functions may be templates.templates.

Page 4: C++ Training Datascope Lawrence D’Antonio

Template Functions

template<class T>

T max(T a, T b) {

return a > b ? a : b;

}

Page 5: C++ Training Datascope Lawrence D’Antonio

Is this legal?

int a,b = 6;

const int c = 3;

double x,y = 3.2;

a = max(b,4);

a = max(b,c);

x = max(y,3.3);

x = max(b,y);

Page 6: C++ Training Datascope Lawrence D’Antonio

a = max(b,4); //Legal, max<int,int>a = max(b,c); //Legal, max<int,int>x = max(y,3.3); //Legal, max<double,double>x = max(b,y); //Illegal, no max<int,double>

A template function is called only when there is an exact match for type parameters (only trivial conversions, such as const int to int are allowed). But the following is legal.

x = max<double>(4,4.2);

Page 7: C++ Training Datascope Lawrence D’Antonio

Better max?template<class S, class T>T max(S a, T b) { return a > b ? a : b;}

main() { int a, b = 3; double x, y = 3.2;

a = max(b,5); x = max(y,5.4); x = max(b,y); x = max(y,b); return 0;}

Page 8: C++ Training Datascope Lawrence D’Antonio

a = max(b,5); //Legal, returns 5

x = max(y,5.4); //Legal, returns 5.4

x = max(b,y); //Legal, 3.2

x = max(y,b); //Legal, but //returns 3.0!

Page 9: C++ Training Datascope Lawrence D’Antonio

Best max?template<class R, class S, class T>R max(S a, T b) { return a > b ? a : b;}

main() { int a, b = 3; double x, y = 3.2;

a = max(b,5); x = max(y,5.4); x = max(b,y); x = max(y,b); return 0;}

Page 10: C++ Training Datascope Lawrence D’Antonio

Doesn’t compile. The function max() is supposed to have 3 template parameters. But each call only uses 2 parameters.

Page 11: C++ Training Datascope Lawrence D’Antonio

Try this maxtemplate<class R, class S, class T>R max(S a, T b) { return a > b ? a : b;}

main() { int a, b = 3; double x, y = 3.2;

a = max<int>(b,5); x = max<double>(y,5.4); x = max<double>(b,y); x = max<double>(y,b);

return 0;}

Page 12: C++ Training Datascope Lawrence D’Antonio

Is this legal?

Return back to the original definition of max.

int x = 5, y = 6;

int *p = &x, *q = &y;

int z = max(p,q);

Page 13: C++ Training Datascope Lawrence D’Antonio

Legal, but probably not what you want.

max(p,q) compares addresses, not data values.

Page 14: C++ Training Datascope Lawrence D’Antonio

Can we fix this?

template<class T>

T max(T a, T b)

{ return a > b ? a : b; }

template<class T>

T* max<T *a, T *b>

{ return *a > *b ? a : b; }

Page 15: C++ Training Datascope Lawrence D’Antonio

Should we fix this?

Probably not. Overloading the max function to compare dereferenced pointers means that we can’t compare addresses using max.

Page 16: C++ Training Datascope Lawrence D’Antonio

STL version of max

template<class T>

const T &max(const T &a, const T &b)

{ return a < b ? b : a; }

Page 17: C++ Training Datascope Lawrence D’Antonio

Another problem

const char *s = “Hello”;

const char *t = “World”;

std::string s = max(s,t);

std::cout << s;

What does this print out?

Who knows? max returns the char* with the larger memory address.

Page 18: C++ Training Datascope Lawrence D’Antonio

A Solution

Overload the max function. The second is called a template specialization.

template<class T>

const T& max(const T&a, const T&b)

{ return a < b ? b : a; }

const char* max(const char *a,const char* b)

{ return std::strcmp(a,b) < 0 ? b : a; }

Page 19: C++ Training Datascope Lawrence D’Antonio

STL Solution

template<class T>

const T& max(const T&a, const T&b)

{ return a < b ? b : a; }

template<class T, class BinPred>

const T& max(const T&a, const T&b, BinPred comp)

{ return comp(a,b) ? b : a; }

Page 20: C++ Training Datascope Lawrence D’Antonio

Using a predicate

bool comp(const char *a, const char *b)

{

return std::strcmp(a,b) < 0;

}

const char *s = “Hello”;

const char *t = “World”;

std::string s = max(s,t,comp);

Page 21: C++ Training Datascope Lawrence D’Antonio

Functor solution

class Comp {

public:

bool operator()(const char *a,

const char *b)

{ return std::strcmp(a,b) < 0; }

};

const char *s = “Hello”;

const char *t = “World”;

std::string s = max(s,t,Comp());

Page 22: C++ Training Datascope Lawrence D’Antonio

Is this legal?

std::string s1(“apple”);

std::string s2(“tomato”);

std::max(“apple”,”peach”);

std::max(“apple”,”tomato”);

std::max(“apple”,s1);

std::max(s1,s2);

Page 23: C++ Training Datascope Lawrence D’Antonio

std::max(“apple”,”peach”);//Legal, both arguments are const char[5]

std::max(“apple”,”tomato”);//Illegal, arguments are different types

std::max(“apple”,s1);//Illegal, arguments are different types

std::max(s1,s2);//Legal, both arguments are type string

Page 24: C++ Training Datascope Lawrence D’Antonio

Is this legal?template<class T>T foo(){ return T(); }

template<class T>void bar(){ T t;

}

main() { int x = foo(); bar();

return 0;}

Page 25: C++ Training Datascope Lawrence D’Antonio

Not legal for two reasons.

int x = foo();

Illegal because the compiler doesn’t know which version of foo() to call. It won’t determine that foo() should return an int by looking at the LHS.

bar();

Illegal because the compiler doesn’t know which version of bar() to call.

Page 26: C++ Training Datascope Lawrence D’Antonio

Legal version of exampletemplate<class T>T foo(){ return T(); }

template<class T>void bar(){ T t;

}

main() { int x = foo<int>(); bar<int>();

return 0;}

Page 27: C++ Training Datascope Lawrence D’Antonio

Template name lookup

Template name resolution involves what is known as “two-phase name lookup”.

Template names are divided into two categories: dependent and non-dependent names.

Dependent and non-dependent names are resolved at different times.

Page 28: C++ Training Datascope Lawrence D’Antonio

Dependent names

Dependent names have definitions that depend on template parameters, but have no declaration within the template definition.

Dependent names are only resolved at the time of instantiation.

Page 29: C++ Training Datascope Lawrence D’Antonio

Non-dependent names

Non-dependent names are names that don’t depend on a template parameter, the name of the template itself, and names declared within it (members, friends, and local variables).

Page 30: C++ Training Datascope Lawrence D’Antonio

Exampletemplate<class T>class X {

T t;public:

X(const T &a):t(a) { t.init(); }

template<class U>T foo() {

U u = t.begin();return *u;

}};

Page 31: C++ Training Datascope Lawrence D’Antonio

Name resolution in example

Non-dependent names

X, t, a, X(const T &), foo(), U,

u

Dependent names

T::init(), T::begin()

Page 32: C++ Training Datascope Lawrence D’Antonio

SFINAE

“Substitution failure is not an error.” When examining which template function

to call from a set of overloaded template functions, there is no error if some substitutions are illegal.

Page 33: C++ Training Datascope Lawrence D’Antonio

Exampletemplate<class Func, class T>void apply(Func f, T x){ f(x); }

template <class T>void multi(T) { }

template <class T*>void multi(T *) { }

main() {apply(multi<int>,5);return 0;

}

Page 34: C++ Training Datascope Lawrence D’Antonio

apply(multi<int>,5) calls multi(T) with int substituting for T. The failure of the substitution of int in multi(T*) does cause an error.

Page 35: C++ Training Datascope Lawrence D’Antonio

Is this legal?

template<int N>int g() { return N; }

template<int *P>int g() { return *P; }

main(){ return g<1>();}

Page 36: C++ Training Datascope Lawrence D’Antonio

Yes, this is legal (if odd looking). g<1> binds to g<int>, the failure to bind to g<int *> is not an error.

Page 37: C++ Training Datascope Lawrence D’Antonio

Is this legal?

template <class Alloc>

class container_helper

{

typedef Alloc::value_type value_type;

};

Page 38: C++ Training Datascope Lawrence D’Antonio

Not legal, the compiler has no idea what the dependent name Alloc::value_type represents. Here is the correct version.

template <class Alloc>class container_helper{

typedef typename Alloc::value_type value_type;};

Page 39: C++ Training Datascope Lawrence D’Antonio

Is this legal?

template <class Alloc>

class container_helper

{

typedef typename Alloc::value_type

value_type;

typedef

std::pair<value_type,value_type> element_type;

};

Page 40: C++ Training Datascope Lawrence D’Antonio

Yes, this is legal.

typedef std::pair<value_type,value_type>

element_type;

This can be resolved in scope.

Page 41: C++ Training Datascope Lawrence D’Antonio

Is this legal?

template <class Alloc>

class container_helper

{

typedef typename Alloc::value_type

value_type;

typedef

std::pair<value_type,value_type> element_type;

typedef typename

Alloc::rebind<element_type>::other

element_allocator;

};

Page 42: C++ Training Datascope Lawrence D’Antonio

Not legal, perhaps surprisingly. The compiler cannot determine from

Alloc::rebind<element_type>::other

what rebind refers to (is it an object, a function, or Superman?).

Page 43: C++ Training Datascope Lawrence D’Antonio

ADL

Argument-dependent lookup applies to unqualified names where it appears that a nonmember function is being called.

ADL proceeds by looking up a name in namespaces and classes associated with the types of the function call arguments.

Page 44: C++ Training Datascope Lawrence D’Antonio

Which functions are called?#include <iostream>

namespace X { template <class T> void f(T) { std::cout << "f<T>\n"; }}

namespace N { using namespace X; enum E{ e1 }; void f(E) { std::cout << "f(E)\n"; }}

void f(int) { std::cout << "f(int)\n"; }

main() { ::f(N::e1); f(N::e1); return 0;}

Page 45: C++ Training Datascope Lawrence D’Antonio

::f(N::e1);//Qualified name, so calls global f, no ADL used

f(N::e1);//Calls N::f. The call argument N::e1 is associated //with namespace N. So this means that N::f is //preferred over ::f. Note that X::f is not considered, //because using directives are ignored in ADL.

Page 46: C++ Training Datascope Lawrence D’Antonio

Is this legal?

template<typename T,

typename Alloc = std::allocator<T> > class my_container : private

container_helper<Alloc>::element_allocator

{

//...

};

Page 47: C++ Training Datascope Lawrence D’Antonio

Perhaps surprisingly this is legal. The dependent name

container_helper<Alloc>::element_allocator

cannot be resolved,. But since it is being used as a base class, the compiler is happy.

Page 48: C++ Training Datascope Lawrence D’Antonio

What is rebind?

A template typedef.template <class T> class allocator { . . . template <class U> struct rebind { typedef allocator<U> other; }; ... template <class U> allocator(const allocator<U>&);

};

Page 49: C++ Training Datascope Lawrence D’Antonio

Use of rebind

template <class T, class Allocator = allocator<T> >

class list {

private:

typedef . . . listnode;

typedef typename Allocator::rebind<listnode>::other

Node_allocator;

Node_allocator alloc_;

list_node* make_node()

{ return new(alloc_.allocate(1)) list_node; }

public:

list(const Allocator& a = Allocator()) : alloc_(a) { } // implicit conversion . . .

};

Page 50: C++ Training Datascope Lawrence D’Antonio

Template classes

The declaration and definition of a template class “must” be in the same header file.

Page 51: C++ Training Datascope Lawrence D’Antonio

For example

//stack.h

template <class T>

class Stack {

public:

T pop();

};

Page 52: C++ Training Datascope Lawrence D’Antonio

//stack.cpp

#include “stack.h”

template <class T>

T Stack<T>::pop()

{

//...

}

Page 53: C++ Training Datascope Lawrence D’Antonio

//main.cpp

#include “stack.h”

main() {

Stack<int> si;

//Push elements onto si

int x = si.pop(); //Illegal!

Page 54: C++ Training Datascope Lawrence D’Antonio

What happened?

No function Stack<int>::pop() defined.

When stack.cpp compiled, no definition for Stack<T> is created. This is because no instantiations exist.

Since main.cpp uses Stack<int>, the compiler instantiates a definition for Stack<int>, but not for the member functions in Stack.cpp!

Page 55: C++ Training Datascope Lawrence D’Antonio

Can we fix this?

export keyword

//stack.h

export template <class T>

class Stack {

public:

T pop();

};

Page 56: C++ Training Datascope Lawrence D’Antonio

What does this do?

The keyword export allows the programmer to put template declarations and template definitions in different translation units.

PROBLEM: Few compilers implement export!

Page 57: C++ Training Datascope Lawrence D’Antonio

Another solution

Explicit instantiation. It requires knowledge of what template instantiations are needed in main.

Page 58: C++ Training Datascope Lawrence D’Antonio

Example

//stack.h

#ifndef STACK_H#define STACK_H

template <class T>class Stack {public: T pop();};

#endif

Page 59: C++ Training Datascope Lawrence D’Antonio

//mystackdef.h

#ifndef MYSTACKDEF_H#define MYSTACKDEF_H

#include <iostream>#include "mystack.h"

template <class T>T Stack<T>::pop() { std::cout << "Pop\n"; return T();}

#endif

Page 60: C++ Training Datascope Lawrence D’Antonio

//mystackinst.cpp

#include "mystackdef.h"#include <string>

template class Stack<int>;

template std::string Stack<std::string>::pop();

Page 61: C++ Training Datascope Lawrence D’Antonio

//main.cpp

#include "mystack.h"#include <string>

main() { Stack<int> s; Stack<std::string> t;

s.pop(); t.pop(); return 0;}

Page 62: C++ Training Datascope Lawrence D’Antonio

Does that work?

Yes, it works. But it is a burden on the programmer. They must see what specific instantiations are needed in the program.

Page 63: C++ Training Datascope Lawrence D’Antonio

Nontype template parameterstemplate <class T, int N>class Stack{ T arr[N]; int count;public: Stack(): count(0) {} void push(const T &t);};

template <class T, int N>void Stack<T,N>::push(const T &t){ if (count != N) arr[count++] = t;}

Page 64: C++ Training Datascope Lawrence D’Antonio

Is this legal?

main() { Stack<int,10> stack10; Stack<int,20> stack20;

stack10.push(8); stack10.push(-3); stack20.push(11); stack20.push(0); stack20 = stack10; return 0;}

Page 65: C++ Training Datascope Lawrence D’Antonio

Not legal.

stack20 = stack10;

Assignment between Stacks of different types.

Page 66: C++ Training Datascope Lawrence D’Antonio

Is this legal?#include <algorithm>#include <vector>#include <list>

template <class T, int x>T add_val(const T &t){ return t+x; }

main() { std::vector<int> v; std::list<int> l(2);

v.push_back(5); v.push_back(8); std::transform(v.begin(),v.end(),

l.begin(), add_val<int,10>); return 0;}

Page 67: C++ Training Datascope Lawrence D’Antonio

Yes, this is legal.

std::transform copies from vector v to list l, applying the function add_val<int,10> to each element being copied.

Page 68: C++ Training Datascope Lawrence D’Antonio

Nontype parameter Rules

A nontype parameter must be one of the following types:

An integer or enumeration type A pointer type A reference type

Page 69: C++ Training Datascope Lawrence D’Antonio

Is this legal?

int C

class C;

int X;

template <class T>

class X;

struct S;

template <class T>

class S;

Page 70: C++ Training Datascope Lawrence D’Antonio

int Cclass C; //Legal, class and nonclass names

//live in different spaces

int X;template <class T>class X; //Illegal, name conflict

struct S;template <class T>class S; //Illegal name conflict

Page 71: C++ Training Datascope Lawrence D’Antonio

Template Linkage

Class names can be the same as nonclass names

Class templates cannot share names with other program constructs. Templates have linkage, but not “C” linkage.

Page 72: C++ Training Datascope Lawrence D’Antonio

Is this legal?

template <class T>

class Foo {

public:

virtual ~Foo();

template <class U>

virtual void bar(const U&);

};

Page 73: C++ Training Datascope Lawrence D’Antonio

virtual ~Foo(); //Legal, one copy per Foo<T> //instance

template <class U>virtual void bar(const U&);//Illegal, unknown number of versions of//bar() per Foo<T> instance

Conclusion: Member function templates cannot be virtual.

Page 74: C++ Training Datascope Lawrence D’Antonio

Is this legal?template <class T>class Foo {private: T t;public: Foo(T s):t(s) { } T get() const { return t; } template<class U> Foo<T> operator=(const Foo<U> &x) { if ( (void *) this == (void *) &x ) return *this; t = x.get();

return *this; }};

Page 75: C++ Training Datascope Lawrence D’Antonio

What functions are called?

main() { Foo<int> f1(4); Foo<double> f2(5.4); f2 = f1;

Foo<int> f3(6); f1 = f3; return 0;}

Page 76: C++ Training Datascope Lawrence D’Antonio

Foo<int> f1(4); //ctorFoo<double> f2(5.4); //ctorf2 = f1; //User defined operator=

Foo<int> f3(6); //ctorf1 = f3; //Compiler defined operator=

Page 77: C++ Training Datascope Lawrence D’Antonio

Template vs. Nontemplate#include<iostream>

template<class T>void f(T){ std::cout << "Template\n"; }

void f(int){ std::cout << "Nontemplate\n"; }

main(){ f(7); f('a'); return 0;}

Page 78: C++ Training Datascope Lawrence D’Antonio

f(7);//Calls f(int), in general the nontemplate //version will be preferred

f('a');//Calls f<char>(char), prefers an exact match

Page 79: C++ Training Datascope Lawrence D’Antonio

Template template parameters

template <typename T,

template <typename U,

typename ALLOC = std::allocator<U> >

class CONT = std::deque>

class Stack {

private:

CONT<T> c;

public:

void push(const T &t);

void pop();

T top() const;

Page 80: C++ Training Datascope Lawrence D’Antonio

template <typename T2,

template < typename U,

typename = std::allocator<U> >

class CONT2 = std::deque>

Stack<T,CONT> &operator=(Stack<T2,CONT2> const &s) {

if ((void *)this == (void *)&s) {

return *this

}

Stack<T2,CONT2> tmp(s);

c.clear();

while (!tmp.empty()) {

c.push_front(tmp.top());

tmp.pop();

}

return *this;

}

};

Page 81: C++ Training Datascope Lawrence D’Antonio

Usage

Stack<int> a;

Stack<float> b;

// . . .

b = a;

Stack<int,vector<int> > c;

Stack<float,vector<float> > d;

// . . .

d = c;

Page 82: C++ Training Datascope Lawrence D’Antonio

Is this legal?

class X { };

list<::X> what;

Page 83: C++ Training Datascope Lawrence D’Antonio

Not legal.

list<::X> what;

//This is the same as

list[:X> what;

//<: is a digraph that is the same as

//a [

Page 84: C++ Training Datascope Lawrence D’Antonio

Correct version

list< ::X> what;

Page 85: C++ Training Datascope Lawrence D’Antonio

Template Argument Deduction

First, template parameters are deduced from the argument types in a function call

Next, if all parameters can be correctly deduced from the argument types then these types are used in the rest of the function declaration.

If either step above fails then a substitution failure occurs (but only an error if all substitutions fail).

Page 86: C++ Training Datascope Lawrence D’Antonio

Exampletemplate<class T>typename T::value_type at(const T &a, int i){ return a[i]; }

void f(int *p){ at(p,0); } void g(int *p){ at<int*>(p,0); }

main(){ int a[3];

f(a); g(a); return 0;}

Page 87: C++ Training Datascope Lawrence D’Antonio

This is clearly illegal.

Invoid f(int *p){ at(p,0); }

There is no matching function at(int *&,int)

Invoid g(int *p){ at<int*>(p,0); }

There is no matching function at(int *&,int)

Page 88: C++ Training Datascope Lawrence D’Antonio

Argument-parameter matching

Suppose an actual type A is matched to a parameter type T.

If the argument parameter is a reference then P is the type referenced and A is the type of the argument.

Otherwise P is the declared parameter type and A is determined by decaying types (e.g., arrays go to pointers, const and volatile are ignored).

Page 89: C++ Training Datascope Lawrence D’Antonio

What type is T?template<class T>void f(T) {}

template<class T>void g(T&) {}

main() { double x[20]; const int y = 3;

f(x); g(x); f(y); g(y); f(3); g(3);

return 0;}

Page 90: C++ Training Datascope Lawrence D’Antonio

f(x); // nonreference parameter, T is double*

g(x); // reference parameter, T is double[20]

f(y); // nonreference parameter, T is int

g(y); // reference parameter, T is const int

f(3); // nonreference parameter, T is int

g(3); // reference parameter, ERROR, 3 is not int&

Page 91: C++ Training Datascope Lawrence D’Antonio

Deduced Contexts

Complex type declarations are built up from elementary constructs.

Matching proceeds from the top level construct and recurses through the composing elements.

Type declarations matched in this way are called deduced contexts.

Qualified type names, e.g., Q<T>::X cannot be used to deduce T.

Page 92: C++ Training Datascope Lawrence D’Antonio

What are the deduced types?template<class T>void f1(T*) {}

template<class T, int N>void f2(T(&)[N]) {}

template<class T1, class T2, class T3>void f3(T1 (T2::*)(T3*)) {}

struct S { void f(double *) {}};

void g(int ***p){ bool b[42]; f1(p); f2(b); f3(&S::f);}

Page 93: C++ Training Datascope Lawrence D’Antonio

f1(p); //T is int**

f2(b); //E is bool, N is 42

f3(&S::f); //T1 is void, T2 is S, T3 is double

Page 94: C++ Training Datascope Lawrence D’Antonio

Is this legal?template<int N>class X {public: typedef int I; void f(int) {}};

template<int N>void fppm(void (X<N>::*)(X<N>::I)) {}

main() { fppm(&X<33>::f);

return 0;}

Page 95: C++ Training Datascope Lawrence D’Antonio

No,

The compiler cannot determine the type of the qualified expression

X<N>::I

Page 96: C++ Training Datascope Lawrence D’Antonio

OK, is this legal?template<int N>class X {public: typedef int I; void f(int) {}};

template<int N>void fppm(void (X<N>::*)(typename X<N>::I)) {}

main() { fppm(&X<33>::f);

return 0;}

Page 97: C++ Training Datascope Lawrence D’Antonio

Yes, this is legal (but complicated).

How does it match types in the expression?

fppm(&X<33>::f);

X<N>::I is a nondeduced context, but the compiler can use the deduced context X<N>::* to determine the parameter N and then plug that into the nondeduced context.

Page 98: C++ Training Datascope Lawrence D’Antonio

Is this legal?template<class T>class B {};

template<class T>class D: public B<T>{};

template<class T>void f(B<T> *) {}

template<class T>void g(D<T> d) { f(&d);}

Page 99: C++ Training Datascope Lawrence D’Antonio

Yes this is legal.

f(&d) is legal because a D<T> can be converted to a B<T>

Page 100: C++ Training Datascope Lawrence D’Antonio

Which template is used?

template<class T>

void f(T) {}

template<class T>

void f(T*) {}

main() {

f(0);

f((int*)0);

}

Page 101: C++ Training Datascope Lawrence D’Antonio

f(0); //Calls f<int>(int)

f((int*)0); //Has two possibilities//f<int*>(int*) or f<int>(int*)//The second function is considered//the “more specialized”

Page 102: C++ Training Datascope Lawrence D’Antonio

More specialized templates

In the previous example, consider possible argument types A1, A2*

A2* can match f<T>(T) (with T = A2*) or can match f<T>(T*) (with T = A2).

But A1 can only match f<T>(T) (with T = A1).

Hence f<T>(T*) is more specialized.

Page 103: C++ Training Datascope Lawrence D’Antonio

Full Class Specializationtemplate<class T>class Types {public: typedef int I;};

template<class T, class U = class Types<T>::I>class S;

template<>class S<void> { };

template<> class S<char,char>;

template<> class S<char,0>;

Page 104: C++ Training Datascope Lawrence D’Antonio

main() { S<int>* psi; S<int> si; S<void>* psv; S<void,int> svi; S<void,char> svc; S<char,char> scc; return 0;}

template<>class S<char,char> {};

Page 105: C++ Training Datascope Lawrence D’Antonio

Which are legal?

template<>

class S<void> { };

//Legal, T = void, U = Types<void>::I

template<> class S<char,char>;

//Legal. T = char, U = char

template<> class S<char,0>;

//Illegal, T = char, but 0 is not a U

Page 106: C++ Training Datascope Lawrence D’Antonio

Which are legal?

S<int>* psi;

//Legal, uses S<T,U>, no definition needed

S<int> si;

//Illegal, uses S<T,U> but no definition //available

S<void>* psv;

//Legal, uses S<void>

Page 107: C++ Training Datascope Lawrence D’Antonio

Which are legal?

S<void,int> svi;

//Legal, uses S<void>, definition available

S<void,char> svc;

//Illegal, uses S<T,U>, no definition

S<char,char> scc;

//Illegal, no definition available

Page 108: C++ Training Datascope Lawrence D’Antonio

Is this legal?

template<>class S<char**> { public: void foo() const;};

template<>void S<char**>::foo() const{ }

Page 109: C++ Training Datascope Lawrence D’Antonio

Not legal.

template<>void S<char**>::foo() const{ }

This is an “invalid function declaration”.

Correct syntax is

void S<char**>::foo() const{ }

Page 110: C++ Training Datascope Lawrence D’Antonio

Is this legal?template<class T>class Outside {public: template<class U> class Inside {};};

template<>class Outside<void> {public: template<class U> class Inside { static int x; };};

template<class U>int Outside<void>::Inside<U>::x = 1;

Page 111: C++ Training Datascope Lawrence D’Antonio

(1) It’s okay that Outside<T>::Inside<U> and Outside<void>::Inside<U> are completely unrelated.

(2) A template class can have static members. Each instance of the class has it’s own version of the static member.

(3) The definition of Inside<U>::x is not preceded by template<>

Page 112: C++ Training Datascope Lawrence D’Antonio

Is this legal?

class Invalid {};

Invalid<double> x;

template<>

class Invalid<double>;

Page 113: C++ Training Datascope Lawrence D’Antonio

Not legal.

Specialization of Invalid<double> after instantiation.

Page 114: C++ Training Datascope Lawrence D’Antonio

Is this legal?#include<iostream>

template<class T>int f(T, T x = 42) { return x; }

template<>int f(int, int = 35) { return 0; }

template<class T>int g(T, T x = 42) { return x; }

template<>int g(int, int y) { return y/2; }

main() { std::cout << g(0) << '\n'; return 0;}

Page 115: C++ Training Datascope Lawrence D’Antonio

Not legal. A template function specialization cannot include default argument values.

template<class T>int f(T, T x = 42) { return x; }

template<>int f(int, int = 35) { return 0; }

Page 116: C++ Training Datascope Lawrence D’Antonio

Explicit Specialization

Member templates, static data members, and member functions of class templates may be specialized.

Page 117: C++ Training Datascope Lawrence D’Antonio

Is this legal?#include <iostream>

template<class T>class Foo { static int x;public: void bar() { std::cout << "Where am I?\n"; }};

template<class T>int Foo<T>::x = 4;

template<>int Foo<int>::x;

template<>void Foo<bool>::bar();

main() { return 0; }

Page 118: C++ Training Datascope Lawrence D’Antonio

This is legal (perhaps surprisingly).

Static members and member functions can be given different definitions for specialized classes.

Nondefining out-of-class declarations are allowed for member functions or static data members.

Page 119: C++ Training Datascope Lawrence D’Antonio

Is this legal?#include <iostream>

template<class T>class Foo { static int x;public: void bar() { std::cout << " Where am I?\n"; }}; template<class T> int Foo<T>::x = 4;

template<>class Foo<void> { double y;public: void bar() { std::cout << x << (y = 3.415) << '\n'; }};

main() { Foo<void> fv; fv.bar();

return 0;}

Page 120: C++ Training Datascope Lawrence D’Antonio

Illegal.

Foo<void> does not have a data member x.

Page 121: C++ Training Datascope Lawrence D’Antonio

Is this legal?template<class T>class Foo { static int x;public: void bar() { std::cout << "Where am I?\n"; }}; template<class T> int Foo<T>::x = 4;

template<> int Foo<int>::x; template<> void Foo<bool>::bar();

main() { Foo<int> fi; fi.bar(); Foo<bool> fb;

}

Page 122: C++ Training Datascope Lawrence D’Antonio

Foo<int> fi;//Legal, Foo<int> doesn’t need to define//static int x

fi.bar();//Legal, Calls Foo<T>::bar()

Foo<bool> fb;//Legal, Foo<bool> doesn’t need to define//member function bar()

Page 123: C++ Training Datascope Lawrence D’Antonio

Example

template<class T>class Outer {public: template<class U> class Inner { private: static int count; };};

Page 124: C++ Training Datascope Lawrence D’Antonio

Is this legal?template<>int Outer<void>::Inner::count = 7;

template<>template<>int Outer<void>::Inner<char>::count = 7; template<>template<>class Outer<int>::Inner<double> {public: enum { ecount = 1 }; Inner() { std::cout << "Inner<double>\n"; }};

Page 125: C++ Training Datascope Lawrence D’Antonio

template<>int Outer<void>::Inner::count = 7;//Not legal. Inner must have a type.

template<>template<>int Outer<void>::Inner<char>::count = 7;//Legal, but template classes have explicit//specialization template<>template<>class Outer<int>::Inner<double> { }//Legal, Inner allowed to be redefined.

Page 126: C++ Training Datascope Lawrence D’Antonio

Is this legal?

template<>template<class T>class Outer<char *>::Inner {public: static long count; };

template<>template<class T>long Outer<char *>::Inner<T>::count = 6L;

Page 127: C++ Training Datascope Lawrence D’Antonio

template<>template<class T>class Outer<char *>::Inner {}//Not legal, Inner should be Inner<T>

template<>template<class T>long Outer<char *>::Inner<T>::count = 6L;//Legal, Inner<T> allowed to define count

Page 128: C++ Training Datascope Lawrence D’Antonio

Is this legal?

template<class T>

template<>

class Outer<T>::Inner<void>;

Page 129: C++ Training Datascope Lawrence D’Antonio

Not legal.

template<> cannot follow after a template parameter list.

Page 130: C++ Training Datascope Lawrence D’Antonio

Is this legal?template<class T = float, int i = 5> class A { public: A() {} };

template<> class A<> { public: A() {} };

main() {A<int,6> x; A<> y;

return 0;}

Page 131: C++ Training Datascope Lawrence D’Antonio

A<int,6> x; //Legal, T = int, i = 6

A<> y;//Legal, uses default arguments, //T = float, i = 5

Page 132: C++ Training Datascope Lawrence D’Antonio

Partial Specializationtemplate<class T>class List {}; //Primary template

template<class T>class List<T*> { //Partial specializationprivate: List<void*> impl;public: void append(T* p) { impl.append(p); }};

template<>class List<void*> { //Full specializationpublic: void append(void *p) { ... }};

Page 133: C++ Training Datascope Lawrence D’Antonio

Further specializationstemplate<class C>class List<void * C::*> {//Partial specializationpublic: typedef void * C::* ElementType; void append(ElementType pm);};

template<class T, class C>class List<T * C::*> { //Partial specializationprivate: List<void* C::*> impl;public: typedef T* C::* ElementType void append(ElementType pm) { impl.append( (void* C::*)pm); }};

Page 134: C++ Training Datascope Lawrence D’Antonio

Partial Specialization Rules

The arguments of the partial specialization must match in kind (type, nontype, template) with the correspnding parameters of the primary template.

No default arguments. Nontype arguments must be

nondependent or plain (no expressions) Argument list must be different from the

primary template.

Page 135: C++ Training Datascope Lawrence D’Antonio

Exampletemplate<class T, int i = 3>class S; //primary template

template<class T>class S<int, T>; //Illegal, parameter mismatch template<class T = int>class S<T,10>; //Illegal, no default arguments

template<int I>class S<int, I*2>; //Illegal, no nontype expressions

template<class U, int W>class S<U,W>; //Illegal, same as primary template

Page 136: C++ Training Datascope Lawrence D’Antonio

Template Error Messages#include <list>#include <string>#include <functional>#include <algorithm>

main() { std::list<std::string> l;

l.push_back("Hello"); l.push_back("World"); std::list<std::string>::iterator pos;

pos = find_if(l.begin(), l.end(), std::bind2nd(std::greater<int>(),"A"));

return 0;}

Page 137: C++ Training Datascope Lawrence D’Antonio

/opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.5/../../../../include/c++/3.4.5/bits/stl_algo.h: In function `_InputIterator std::find_if(_InputIterator, _InputIterator, _Predicate, std::input_iterator_tag) [with _InputIterator = std::_List_iterator<std::string>, _Predicate = std::binder2nd<std::greater<int> >]':/opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.5/../../../../include/c++/3.4.5/bits/stl_algo.h:336: instantiated from `_InputIterator std::find_if(_InputIterator, _InputIterator, _Predicate) [with _InputIterator = std::_List_iterator<std::string>, _Predicate = std::binder2nd<std::greater<int> >]'error.cpp:14: instantiated from here/opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.5/../../../../include/c++/3.4.5/bits/stl_algo.h:187: error: no match for call to `(std::binder2nd<std::greater<int> >) (std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'/opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.5/../../../../include/c++/3.4.5/bits/stl_function.h:440: note: candidates are: typename _Operation::result_type std::binder2nd<_Operation>::operator()(const typename _Operation::first_argument_type&) const [with _Operation = std::greater<int>]/opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.5/../../../../include/c++/3.4.5/bits/stl_function.h:446: note: typename _Operation::result_type std::binder2nd<_Operation>::operator()(typename _Operation::first_argument_type&) const [with _Operation = std::greater<int>]


Recommended