C training datascope lawrence d antonio
This presentation is the property of its rightful owner.
Sponsored Links
1 / 137

C++ Training Datascope Lawrence D’Antonio PowerPoint PPT Presentation


  • 97 Views
  • Uploaded on
  • Presentation posted in: General

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.

Download Presentation

C++ Training Datascope Lawrence D’Antonio

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


C training datascope lawrence d antonio

C++ TrainingDatascopeLawrence D’Antonio

Lecture 7

An Overview of C++:

What is Polymorphism? –

Parametric Polymorphism


What is polymorphism

What is polymorphism?

Parametric

Universal

Subtype

Polymorphism

Overloading

Ad-hoc

Coercion

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


Parametric polymorphism

Parametric Polymorphism

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

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

  • Both classes and functions may be templates.


Template functions

Template Functions

template<class T>

T max(T a, T b) {

return a > b ? a : b;

}


Is this legal

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


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


Better max

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;

}


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!


Best max

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;

}


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.


Try this max

Try this 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<int>(b,5);

x = max<double>(y,5.4);

x = max<double>(b,y);

x = max<double>(y,b);

return 0;

}


Is this legal1

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


C training datascope lawrence d antonio

Legal, but probably not what you want.

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


Can we fix this

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

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

STL version of max

template<class T>

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

{return a < b ? b : a; }


Another problem

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

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

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

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

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 legal2

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


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


Is this legal3

Is this legal?

template<class T>

T foo()

{ return T(); }

template<class T>

void bar()

{

T t;

}

main() {

int x = foo();

bar();

return 0;

}


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.


Legal version of example

Legal version of example

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

  • 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

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


Example

Example

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

Name resolution in example

  • Non-dependent names

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

    u

  • Dependent names

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


Sfinae

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.


Example1

Example

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

}


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.


Is this legal4

Is this legal?

template<int N>

int g() { return N; }

template<int *P>

int g() { return *P; }

main()

{

return g<1>();

}


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.


Is this legal5

Is this legal?

template <class Alloc>

class container_helper

{

typedef Alloc::value_type value_type;

};


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;

};


Is this legal6

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;

};


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.


Is this legal7

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;

};


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


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.


Which functions are called

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;

}


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.


Is this legal8

Is this legal?

template<typename T,

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

container_helper<Alloc>::element_allocator

{

//...

};


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.


What is rebind

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

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

Template classes

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


For example

For example

//stack.h

template <class T>

class Stack {

public:

T pop();

};


C training datascope lawrence d antonio

//stack.cpp

#include “stack.h”

template <class T>

T Stack<T>::pop()

{

//...

}


C training datascope lawrence d antonio

//main.cpp

#include “stack.h”

main() {

Stack<int> si;

//Push elements onto si

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


What happened

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 this1

Can we fix this?

  • export keyword

    //stack.h

    export template <class T>

    class Stack {

    public:

    T pop();

    };


What does this do

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

Another solution

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


Example2

Example

//stack.h

#ifndef STACK_H

#define STACK_H

template <class T>

class Stack {

public:

T pop();

};

#endif


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


C training datascope lawrence d antonio

//mystackinst.cpp

#include "mystackdef.h"

#include <string>

template class Stack<int>;

template

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


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;

}


Does that work

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 parameters

Nontype template parameters

template <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 legal9

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;

}


C training datascope lawrence d antonio

Not legal.

stack20 = stack10;

Assignment between Stacks of different types.


Is this legal10

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;

}


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.


Nontype parameter rules

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 legal11

Is this legal?

int C

class C;

int X;

template <class T>

class X;

struct S;

template <class T>

class S;


C training datascope lawrence d antonio

int C

class 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

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 legal12

Is this legal?

template <class T>

class Foo {

public:

virtual ~Foo();

template <class U>

virtual void bar(const U&);

};


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.


Is this legal13

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

What functions are called?

main() {

Foo<int> f1(4);

Foo<double> f2(5.4);

f2 = f1;

Foo<int> f3(6);

f1 = f3;

return 0;

}


C training datascope lawrence d antonio

Foo<int> f1(4); //ctor

Foo<double> f2(5.4); //ctor

f2 = f1; //User defined operator=

Foo<int> f3(6); //ctor

f1 = f3; //Compiler defined operator=


Template vs nontemplate

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;

}


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


Template template parameters

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;


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;

}

};


Usage

Usage

Stack<int> a;

Stack<float> b;

// . . .

b = a;

Stack<int,vector<int> > c;

Stack<float,vector<float> > d;

// . . .

d = c;


Is this legal14

Is this legal?

class X { };

list<::X> what;


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 [


Correct version

Correct version

list< ::X> what;


Template argument deduction

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


Example3

Example

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

}


C training datascope lawrence d antonio

This is clearly illegal.

In

void f(int *p)

{ at(p,0); }

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

In

void g(int *p)

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

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


Argument parameter matching

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

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;

}


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&


Deduced contexts

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

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

}


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


Is this legal15

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;

}


C training datascope lawrence d antonio

No,

The compiler cannot determine the type of the qualified expression

X<N>::I


Ok is this legal

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;

}


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.


Is this legal16

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

}


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>


Which template is used

Which template is used?

template<class T>

void f(T) {}

template<class T>

void f(T*) {}

main() {

f(0);

f((int*)0);

}


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”


More specialized templates

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 specialization

Full Class Specialization

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


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


Which are legal

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 legal1

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 legal2

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 legal17

Is this legal?

template<>

class S<char**> {

public:

void foo() const;

};

template<>

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

{ }


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

{ }


Is this legal18

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;


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


Is this legal19

Is this legal?

class Invalid {};

Invalid<double> x;

template<>

class Invalid<double>;


C training datascope lawrence d antonio

Not legal.

Specialization of Invalid<double> after instantiation.


Is this legal20

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;

}


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


Explicit specialization

Explicit Specialization

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


Is this legal21

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


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.


Is this legal22

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;

}


C training datascope lawrence d antonio

Illegal.

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


Is this legal23

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;

}


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


Example4

Example

template<class T>

class Outer {

public:

template<class U>

class Inner {

private:

static int count;

};

};


Is this legal24

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

};


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.


Is this legal25

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;


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


Is this legal26

Is this legal?

template<class T>

template<>

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


C training datascope lawrence d antonio

Not legal.

template<> cannot follow after a template parameter list.


Is this legal27

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;

}


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


Partial specialization

Partial Specialization

template<class T>

class List {}; //Primary template

template<class T>

class List<T*> { //Partial specialization

private:

List<void*> impl;

public:

void append(T* p) { impl.append(p); }

};

template<>

class List<void*> { //Full specialization

public:

void append(void *p) { ... }

};


Further specializations

Further specializations

template<class C>

class List<void * C::*> {//Partial specialization

public:

typedef void * C::* ElementType;

void append(ElementType pm);

};

template<class T, class C>

class List<T * C::*> { //Partial specialization

private:

List<void* C::*> impl;

public:

typedef T* C::* ElementType

void append(ElementType pm)

{ impl.append( (void* C::*)pm); }

};


Partial specialization rules

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.


Example5

Example

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

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;

}


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


  • Login