c++ training datascope lawrence d’antonio lecture 7 an overview of c++: what is polymorphism? –...

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

Post on 21-Dec-2015

222 views

Category:

Documents


2 download

TRANSCRIPT

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

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

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.

Template Functions

template<class T>

T max(T a, T b) {

return a > b ? a : b;

}

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);

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);

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;}

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!

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;}

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

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;}

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);

Legal, but probably not what you want.

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

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; }

Should we fix this?

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

STL version of max

template<class T>

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

{ return a < b ? b : a; }

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.

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; }

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; }

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);

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());

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);

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

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

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

}

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

return 0;}

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.

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;}

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.

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.

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).

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;

}};

Name resolution in example

Non-dependent names

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

u

Dependent names

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

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.

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;

}

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.

Is this legal?

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

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

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

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

Is this legal?

template <class Alloc>

class container_helper

{

typedef Alloc::value_type value_type;

};

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;};

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;

};

Yes, this is legal.

typedef std::pair<value_type,value_type>

element_type;

This can be resolved in scope.

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;

};

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?).

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.

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;}

::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.

Is this legal?

template<typename T,

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

container_helper<Alloc>::element_allocator

{

//...

};

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.

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>&);

};

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

};

Template classes

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

For example

//stack.h

template <class T>

class Stack {

public:

T pop();

};

//stack.cpp

#include “stack.h”

template <class T>

T Stack<T>::pop()

{

//...

}

//main.cpp

#include “stack.h”

main() {

Stack<int> si;

//Push elements onto si

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

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!

Can we fix this?

export keyword

//stack.h

export template <class T>

class Stack {

public:

T pop();

};

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!

Another solution

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

Example

//stack.h

#ifndef STACK_H#define STACK_H

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

#endif

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

//mystackinst.cpp

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

template class Stack<int>;

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

//main.cpp

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

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

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

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.

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;}

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;}

Not legal.

stack20 = stack10;

Assignment between Stacks of different types.

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;}

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.

Nontype parameter Rules

A nontype parameter must be one of the following types:

An integer or enumeration type A pointer type A reference type

Is this legal?

int C

class C;

int X;

template <class T>

class X;

struct S;

template <class T>

class S;

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

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.

Is this legal?

template <class T>

class Foo {

public:

virtual ~Foo();

template <class U>

virtual void bar(const U&);

};

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.

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; }};

What functions are called?

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

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

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

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

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;}

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

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

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;

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;

}

};

Usage

Stack<int> a;

Stack<float> b;

// . . .

b = a;

Stack<int,vector<int> > c;

Stack<float,vector<float> > d;

// . . .

d = c;

Is this legal?

class X { };

list<::X> what;

Not legal.

list<::X> what;

//This is the same as

list[:X> what;

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

//a [

Correct version

list< ::X> what;

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).

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;}

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)

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).

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;}

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&

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.

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);}

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

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;}

No,

The compiler cannot determine the type of the qualified expression

X<N>::I

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;}

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.

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);}

Yes this is legal.

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

Which template is used?

template<class T>

void f(T) {}

template<class T>

void f(T*) {}

main() {

f(0);

f((int*)0);

}

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”

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.

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

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> {};

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

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>

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

Is this legal?

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

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

Not legal.

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

This is an “invalid function declaration”.

Correct syntax is

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

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;

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

Is this legal?

class Invalid {};

Invalid<double> x;

template<>

class Invalid<double>;

Not legal.

Specialization of Invalid<double> after instantiation.

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;}

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; }

Explicit Specialization

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

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; }

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.

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;}

Illegal.

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

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;

}

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()

Example

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

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"; }};

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.

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;

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

Is this legal?

template<class T>

template<>

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

Not legal.

template<> cannot follow after a template parameter list.

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;}

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

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

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) { ... }};

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); }};

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.

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

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;}

/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>]