zoukankan      html  css  js  c++  java
  • C++模板元编程(一)

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

    参考资料

    1. 《C++模板元编程》(David Abrahams, Aleksey Gurtovoy )
    2. c++模板元编程2
  • 相关阅读:
    rpm命令详解
    Linux基础提高_系统性能相关命令
    Day004_Linux基础命令之特殊符号与正则表达式通配符
    Linux基础_网站权限规划
    Day005_Linux基础之文件权限
    Day003_linux基础_系统启动过程及系统安装后优化
    win7旗舰版安装不了mysql问题-------win7系统版本选择问题的一点探索
    Java程序结构
    NCRE Java二级备考方案
    NCRE的JAVA二级考试大纲
  • 原文地址:https://www.cnblogs.com/corfox/p/5414994.html
Copyright © 2011-2022 走看看