C++模板元编程(一)
2015-12-28 23:34
369 查看
C++模板元编程(一)
首先看一个例子,利用模板元编程递归将无符号二进制数转换为十进制。#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; }
Traits和类型操纵
假设设计一个迭代器的,需要访问迭代器中的类型时。当迭代器是一个类时,可以在其中嵌套指定它的元素类型。但是普通的指针也可以用作合法的迭代器,便不能在其中指定其元素类型。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++模板元编程》)
相关的概念:
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 , 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, 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; }
参考资料
《C++模板元编程》(David Abrahams, Aleksey Gurtovoy )c++模板元编程2
相关文章推荐
- C++四种类型转换
- 好莱坞科幻背景(c语言)
- c++(一)
- C++虚函数与虚函数表
- 《C语言及程序设计》第23讲实践项目
- 常用的C/C++文本文件的读写函数
- C++ 函数内部定义函数原型?
- 【C语言】g++常用编译选项备忘
- HDU5601:N*M bulbs
- 【C++】深度探索C++对象模型之构造、析构、拷贝语意学
- 绘制Android机器人(c语言)
- C语言中#define的用法
- 神一般的C语言指针,你看懂多少?
- 彻底搞定C语言指针详解
- 实战c++中的智能指针unique_ptr系列-- unique_ptr与lambda的错误结合(尤其是捕获lambda中的unique_ptr)
- 实战c++中的智能指针unique_ptr系列-- unique_ptr与lambda的错误结合(尤其是捕获lambda中的unique_ptr)
- Notepad++配置c++、python、java与C#
- C语言: 贪吃蛇异常退出
- Check—强大的C语言单元测试框架
- c++ 静态成员变量