首先看一個例子,利用模板元編程遞歸將無符號二進制數轉換爲十進制。ios
#include<iostream>
using namespace std;
// 遞歸,將無符號二進制轉換爲十進制
//
template<unsigned long N>
class binary
{
public:
static const unsigned int value = binary<N/10>::value * 2 + N % 10;
};
// 特化爲N=0,終止遞歸
template<>
class binary<0>
{
public:
static const unsigned int value = 0;
};
int main()
{
std::cout << binary<101010>::value << std::endl;
return 0;
}
假設設計一個迭代器的,須要訪問迭代器中的類型時。當迭代器是一個類時,能夠在其中嵌套指定它的元素類型。可是普通的指針也能夠用做合法的迭代器,便不能在其中指定其元素類型。c++
template<typename ForwardIterator1, typename ForwardIterator2>
void iterSwap(ForwardIterator1 i1, ForwardIterator i2)
{
typename ForwardIterator1::value_type tmp = *i1;
*i1 = *i2;
*i2 = tmp;
}
能夠在其中引入一箇中間層來解決此問題,經過該中間層進行類型計算來得到不一樣迭代器的元素類型。編程
/************************************************************************* > File Name: traits_test.cpp > Author: corfox > Mail: corfox@163.com > Created Time: 2015/12/27 11:39:56 ************************************************************************/
#include <iostream>
#include <iterator>
#include <cstddef>
using namespace std;
template<typename Tp>
class IteratorTraits
{
public:
//當使用一個依賴性的名字,且該名字表示一個類型時,C++標準要求使用typename關鍵字代表
typedef typename Tp::value_type value_type;
typedef typename Tp::reference reference;
typedef typename Tp::pointer pointer;
typedef typename Tp::difference_type difference_type;
typedef typename Tp::iterator_category iterator_category;
};
// 偏特化Tp爲指針類型
template<typename Tp>
class IteratorTraits<Tp*>
{
public:
typedef Tp value_type;
typedef Tp& reference;
typedef Tp* pointer;
typedef std::ptrdiff_t difference_type;
typedef std::random_access_iterator_tag iterator_category;
};
template<typename ForwardIterator1, typename ForwardIterator2>
void iterSwap(ForwardIterator1 i1, ForwardIterator2 i2)
{
typename IteratorTraits<ForwardIterator1>::value_type tmp = *i1;
*i1 = *i2;
*i2 = tmp;
}
void f(int *p1, int *p2, size_t length)
{
for (size_t i = 0; i < length; ++i)
{
iterSwap(p1++, p2++);
}
}
void showArr(int *p, size_t length)
{
for (size_t i = 0; i < length; ++i)
cout << *p++ << " ";
cout << endl;
}
int main(void)
{
int arr1[5] = { 1, 2, 3, 4, 5 };
int arr2[5] = { 6, 7, 8, 9, 10};
showArr(arr1, 5);
showArr(arr2, 5);
f(arr1, arr2, 5);
showArr(arr1, 5);
showArr(arr2, 5);
return 0;
}
-----
輸出:
1 2 3 4 5
6 7 8 9 10
6 7 8 9 10
1 2 3 4 5
元函數的定義:一個元函數能夠是一個類模板,它的全部參數都是類型;或者一個類,帶有一個名爲「type」的公有嵌套結構類型(result types)。(摘自:《C++模板元編程》)markdown
相關的概念: dom
1. 特化:類模板特化的語法規則template <variable part> class template-name<fixed part>
。顯示特化(explicit specialization)中,variable part是空的,而fixed part則由具體的模板參數構成;在部分特化(partial specilization)中,variable part包含有一個參數列表,fixed part中則至少有一個實參依賴於這些參數。
2. 主模板(primary template):不是一個特化的模板聲明稱爲主模板。
3. 實例化(instantiated):當編譯器須要知道一個模板的更多內容(遠比「其實參是什麼」更多,包括諸如其成員的名字或基類的身份等)時,模板將被實例化。在該時刻,編譯器爲全部模板參數填充實際值,挑選最佳匹配的顯示或部分特化,計算出模板本體內的聲明中使用的全部類型和常量,並覈查這些聲明是否有誤。然而,不到定義(definition)(例如成員函數本體)被使用時,它並不實例化定義。
4. 元數據:可被C++編譯期系統操縱的「值」能夠被認爲是元數據。在模板元編程中,兩種最多見的元數據是類型和整數常量。C++的編譯期部分一般被稱爲純函數式語言,由於元數據是不可變的,而且元函數不能夠有任何反作用。
5. 元函數:一個操縱元數據並能夠在編譯期「調用」的「函數」。
6. Traits:一種經過類模板特化在小片元數據之間創建關聯的技術。函數
/************************************************************************* > File Name: excercise_210.cpp > Author: corfox > Mail: corfox@163.com > Created Time: 2015/12/28 9:59:50 ************************************************************************/
#include <iostream>
#include <type_traits>
#include <cassert>
#include <string>
using namespace std;
// 2-0
struct Test
{
virtual ~Test()
{
}
};
template<typename T>
struct add_const_ref
{
typedef const T& type;
};
template<typename T>
struct add_const_ref<T&>
{
typedef T& type;
};
// 2-1
template<typename T, typename P, typename U, bool same>
struct replace_type_indirect;
template<typename T, typename P, typename U>
struct replace_type
{
static bool const value = std::is_same<T, P>::value;
typedef typename replace_type_indirect<T, P, U, value>::type type;
};
// T與P是相同類型時
template<typename T, typename P, typename U>
struct replace_type_indirect<T, P, U, true>
{
typedef U type;
};
// T與P不是相同類型時
template<typename T, typename P, typename U>
struct replace_type_indirect<T*, P, U, false>
{
typedef typename replace_type<T, P, U>::type* type;
};
template<typename T, typename P, typename U>
struct replace_type_indirect<T&, P, U, false>
{
typedef typename replace_type<T, P, U>::type& type;
};
template<typename T, typename P, typename U>
struct replace_type_indirect<T[], P, U, false>
{
typedef typename replace_type<T, P, U>::type type[];
};
template<typename T, typename P, typename U, int N>
struct replace_type_indirect<T[N], P, U, false>
{
typedef typename replace_type<T, P, U>::type type[N];
};
template<typename T, typename P, typename U>
struct replace_type_indirect<T(), P, U, false>
{
typedef typename replace_type<T, P, U>::type type();
};
template<typename T, typename P, typename U, typename A>
struct replace_type_indirect<T(A), P, U, false>
{
typedef typename replace_type<T, P, U>::type type(
typename replace_type<A, P, U>::type);
};
template<typename T, typename P, typename U, typename A1, typename A2>
struct replace_type_indirect<T(A1, A2), P, U, false>
{
typedef typename replace_type<T, P, U>::type type(
typename replace_type<A1, P, U>::type,
typename replace_type<A2, P, U>::type);
};
// 2-2
template<typename T, typename S>
inline T polymorphic_downcast(S* x)
{
assert(dynamic_cast<T>(x) == x);
return static_cast<T>(x);
}
template<typename T, typename S>
inline T polymorphic_downcast(S& x)
{
assert(dynamic_cast<typename std::add_pointer<
typename std::remove_reference<T>::type>::type>(&x) == &x);
return static_cast<T>(x);
}
struct SubTest : Test
{
};
// 2-3
template<typename T> struct type_descriptor
{
string value;
type_descriptor()
{
value = "The type T cannot be deduced.";
}
operator const char*()
{
return value.c_str();
}
};
template<> struct type_descriptor<int>
{
string value;
type_descriptor()
{
value = "int";
}
operator const char*()
{
return value.c_str();
}
};
template<> struct type_descriptor<short int>
{
string value;
type_descriptor()
{
value = "short int";
}
operator const char*()
{
return value.c_str();
}
};
template<> struct type_descriptor<char>
{
string value;
type_descriptor()
{
value = "char";
}
operator const char*()
{
return value.c_str();
}
};
template<> struct type_descriptor<long int>
{
string value;
type_descriptor()
{
value = "long int";
}
operator const char*()
{
return value.c_str();
}
};
template<typename T> struct type_descriptor<T*>
{
string value;
operator const char*()
{
value = type_descriptor<T>();
value += "*";
return value.c_str();
}
};
template<typename T> struct type_descriptor<T&>
{
string value;
operator const char*()
{
value = type_descriptor<T>();
value += "&";
return value.c_str();
}
};
template<typename T> struct type_descriptor<T const>
{
string value;
operator const char*()
{
value = type_descriptor<T>();
value += " const";
return value.c_str();
}
};
int main(void)
{
cout << "2-0" << endl;
cout << std::boolalpha;
// 測試T是一個引用,返回T
cout << std::is_same<add_const_ref<Test&>::type, Test&>::value << endl;
// 測試T不是一個引用,返回const T&
cout << std::is_same<add_const_ref<Test>::type, Test>::value << endl;
cout << std::is_same<add_const_ref<Test>::type, const Test&>::value << endl;
cout << "2-1" << endl;
cout << std::is_same<replace_type<void*, void, int>::type, int*>::value << endl;
cout << std::is_same<replace_type<int const*[10], int const, long>::type, long*[10]>::value
<< endl;
cout << std::is_same<replace_type<char& (*)(char&), char&, long&>::type, long& (*)(long&)>::value
<<endl;
// 2-2
SubTest b;
Test *a_ptr = &b;
SubTest *b_ptr = polymorphic_downcast<SubTest*>(a_ptr);
Test& a_ref = b;
SubTest& b_ref = polymorphic_downcast<SubTest&>(a_ref);
cout << "2-3" << endl;
cout << type_descriptor<int>() << endl;
cout << type_descriptor<char *>() << endl;
cout << type_descriptor<long const*&>() << endl;
return 0;
}