[ create a new paste ] login | about

Link: http://codepad.org/tiH1e5Y2    [ raw code | output | fork ]

Scheme, pasted on Sep 11:
#include <boost/type_traits.hpp>
using boost::is_same;

/*-------------------------------------------------------------------------------------------------------*/

////////// Full specialization

template <class X>
struct A {};

template <>
struct A<int> {};

////////// Partial specialization

template <class X>
struct A<X*> {};

////////// Specialization of inner classes

struct B {
	template <class X>
	struct Inner {};
};

template <>
struct B::Inner<int> {};

template <class X>
struct B::Inner<X*> {};

////////// ?Nested? specialization plus specialization of inner classes

template <class X>
struct C {
	template <class Y>
	struct Inner {};
};

template <> template <>
struct C<int>::Inner<int> {}; // explicit of inner

template <> template <class Y>
struct C<int>::Inner<Y*> {}; // partial of inner

////////// Inner specialization 3

template <class X>
struct D {
	template <class Y>
	struct Inner {};
};

template <class X> template <class Y>	// ok
struct D<X>::Inner<Y*> {};

/*template <class X> template <>		// NOT ok
struct D<X>::Inner<int> {};*/			// "there could be a first specialization with no Inner."

////////// Default template parameters

template <class X=int>
struct E {};

static_assert(is_same<E<>, E<int>>::value, "!");

//template <class X=int>
//struct E<X*> {};						// default template parameters may not be used in partial special

/*-------------------------------------------------------------------------------------------------------*/

template <class Y>
struct F
{
	////////// Nested templates
	template <class X>
	struct A {};
	
	////////// Explicit special: Not allowed.
	//template <>
	//struct A<int> {};
	
	////////// Nested partial Special
	template <class X>
	struct A<X*> {};
	
	////////// Nested explicit special workaround
	template <class X, class=void>
	struct B {};
	
	template <class _> // default not allowed/needed
	struct B<int, _> {}; // add _ to each pseudo-explicit special
	
	void test_bhack()
	{
		//F::B<bool> b; // illegal.
		
		F<int>::B<bool> a; // works
		typename F<Y>::template B<bool> b; // works
		typename F::template B<bool> c; // works
		
		typename F::template B<int> d; // uses the workaround
		static_assert(is_same<typename F::template B<int>, typename F::template B<int,void>>::value, "!");
	}
	
	////////// Member function templates
	template <class X>
	void f(X);
	
	////////// Member function partial special
	template <class X>
	void f(X*);
	
	////////// Member function template special: Not allowed!
	//template <class X>
	//void f<int>(int);
	
	////////// Member function template special workaround
	template <class X, class=void>
	void g(X);
	
	template <class>
	void g(int);
	
	void test_ghack() {
		g(1); // uses the workaround
	}
};

/*-------------------------------------------------------------------------------------------------------*/

/*
Nontemplate functions are first-class citizens. A plain old nontemplate function that matches the parameter
types as well as any function template will be selected over an otherwise-just-as-good function template.

If there are no first-class citizens to choose from that are at least as good, then function base templates
as the second-class citizens get consulted next. Which function base template gets selected depends on which
matches best and is the "most specialized" (important note: this use of "specialized" oddly enough has
nothing to do with template specializations; it's just an unfortunate colloquialism) according to a set of
fairly arcane rules:
	
	If it's clear that there's one "most specialized" function base template, that one gets used. If that
	base template happens to be specialized for the types being used, the specialization will get used,
	otherwise the base template instantiated with the correct types will be used.
	
	Else if there's a tie for the "most specialized" function base template, the call is ambiguous because
	the compiler can't decide which is a better match. The programmer will have to do something to qualify
	the call and say which one is wanted.
	
	Else if there's no function base template that can be made to match, the call is bad and the programmer
	will have to fix the code."
*/

////////// Function overloading

void e(int=1);
void e(bool);
//int e(int);							// ambiguates old declaration
int e();								// VAGUE with int=1

void test_e() {
	((int(*)())e)();					// to disambiguate the call
}

////////// Templating a function with no dependent parameters

template <class X> void f();

void test_f() {
	f<int>(); // f only callable via f<int>()
}

////////// Multiple function templates

template <class X> X g();				// function template 1
template <> int g();

template <class X> void g(X);			// function template 2
template <> void g(int);

template <class X> void g(X*);			// function template 3
// there's no such thing as a partial specialization of a function template!

void test_g() {
	g<int>(); // template 1
	g(1); // template 2
}

////////// Partial specialization

template <class X> void ff(X);
//template <> void f(X*); // illegal- not partial specialization! Is an overload..
//template <class X> void f<X*>(X*); // "function template partial specialization 'f<X*>' is not allowed"

template <class X> void gg();
//template <class X> void g<X*>(); // Not even this, is allowed.

////////// Function template selection

void h(int);
template <class X> void h(X);
template <> void h(int);				// VAGUE here, but allowed.

void test_h() {
	h(1); // calls void h(int);			// Prefers the non-global
}

////////// Function template explicit specialization

template <class X> void h();
template <> void h<int>();

template <class X> X h();
template <> int h();					// This and,
template <> int h<int>();				// this, are the same template specialization.

template <class X> void h(X);
template <> void h(int);				// declares void i<int>(int);
template <> void h<int>(int) {}			// defines void i<int>(int);

////////// Function template explicit specialization + overloading

template <class X> X i();				// template 1
template <class X> X i(int);			// template 2
template <class X> X i(bool);			// template 3
template <> int i(bool);				// Specialization of template 3

////////// Function template defaults

template <class X=int> void j();
template <class X=int> void k(X = X());	// a
template <> void k(int); // b
//template <> void k(int=0);			// disallowed default argument in explicit specialization

void test_jk() {
	j();	// call j<int>()
	k();	// call b: k<int>(int)
	k(1.1);	// call a: k<double>(double)
}

////////// Function template selection

void l(int); // l1
template <class X> void l(X); // l2
template <> void l(int); // l3

void m(int); // m1
template <class X=int> void m(X=X()); // m2
template <> void m(int); // m3

void n(int=0); // n1
template <class X=int> void n(X=X()); // n2

void test_lmn() {
	l(1);		// l1
	l(true);	// l2
	l<int>(1);	// l3
	//l();		// error
	
	m(1);		// m1
	m(true);	// m2
	m<bool>();	// m2
	m<int>(1);	// m3
	m();		// m3
	
	n();		// n1
}

////////// The resolution scheme:

/*
Specializations don't overload.
Only after it's been decided which base template is going to be selected, and that choice is locked in, will the compiler look around to see if there happens to be a suitable specialization of that template available, and if so that specialization will get used.
*/

template<class T>	// a: base template 1
void o(T);

template<>			// b: explicit special of 1
void o<>(int*);

template <class T>	// c: base template 2, overloads with base template 1
void o(T*);

void test_o() {
	f((int*)0); // calls c!
	// overload resolution ignores specializations and operates on the base function templates only
}

// workaround:

template <class X> 
inline void f(T t) {
	fImpl<T>::f(t);
}

template <class X> // specialize this.
struct fImpl { static void f(X); };

template <>
struct fImpl<int*> { static void f(int*); };

template <class X>
struct fImpl<X*> { static void f(X*); };


Output:
1
Line 1:0: read-number: bad number: nclude


Create a new paste based on this one


Comments: