模板元编程-C++

// 模板
template<class T>
class MyType
{
public:
    int min()
    {
        return 0;
    }

    int max()
    {
        return 9;
    }
};

template<class T>
class MyClass
{
public:
    typedef MyType<T> TYPE;

public:
    TYPE get(); // 返回一个TYPE类型的对象
};

template<class T>
typename MyClass<T>::TYPE MyClass<T>::get() // 注意这个typename
{
    return MyClass<T>::TYPE();
}

void demo1()
{
    MyClass<int> x;
    MyType<int> y = x.get();

    printf("type min: %d, type max: %d\n", y.min(), y.max());
}

// 模板元(递归)
/*
The problem: create a typedef for a signed integral type that is at least nbits in size.
The C++ Way
This example is simplified and adapted from one written by Dr. Carlo Pescio in Template Metaprogramming: Make parameterized integers portable with this novel technique.
There is no way in C++ to do conditional compilation based on the result of an expression based on template parameters, so all control flow follows from pattern matching of the template argument against various explicit template specializations. Even worse, there is no way to do template specializations based on relationships like "less than or equal to", so the example uses a clever technique where the template is recursively expanded, incrementing the template value argument by one each time, until a specialization matches. If there is no match, the result is an unhelpful recursive compiler stack overflow or internal error, or at best a strange syntax error.

A preprocessor macro is also needed to make up for the lack of template typedefs.
*/
#include <limits.h>
template<int nbits>
struct Integer
{
    typedef typename Integer<nbits + 1>::int_type int_type ;
};

template<>
struct Integer<8>
{
    typedef signed char int_type;
} ;

template<>
struct Integer<16>
{
    typedef short int_type;
};

template<>
struct Integer<32>
{
    typedef int int_type;
};

template<>
struct Integer<64>
{
    typedef long long int_type;
};

// If the required size is not supported, the metaprogram
// will increase the counter until an internal error is
// signaled, or INT_MAX is reached. The INT_MAX
// specialization does not define a int_type, so a
// compiling error is always generated
template<>
struct Integer<INT_MAX>
{
};

// A bit of syntactic sugar
#define Integer(nbits) Integer<nbits>::int_type

#include <stdio.h>

void demo2()
{
    Integer(8) i ;
    Integer(16) j ;
    Integer(29) k ;
    Integer(64) l ;
    Integer(20) m; // int型
    printf("%d %d %d %d %d\n",
        sizeof(i), sizeof(j), sizeof(k), sizeof(l), sizeof(m));}

#include <iostream>
using namespace std;
// 1..N的累加
template<int N>
class MyAdd
{
public:
 enum
 {
  fare = MyAdd<N - 1>::fare + N
 };
};

template<>
class MyAdd<0>
{
public:
 enum
 {
  fare = 0
 };
};

// power(N, M):N的M次方
template<int N, int M>
class MyPower
{
public:
 enum
 {
  fare = N * MyPower<N, M - 1>::fare
 };
};
template<int N> // 偏特化
class MyPower<N, 0>
{
public:
 enum
 {
  fare = 1
 };
};

// 菲波那契数列
template<int N>
struct Fib
{
    const static long long fare = Fib<N - 1>::fare + Fib<N - 2>::fare;
};

template<>
struct Fib<1>
{
    const static long long fare = 1;
};

template<>
struct Fib<0>
{
    const static long long fare = 1;
};

// 阶乘 N! = N * (N-1) * ... * 2 * 1
template<int N>
class Factorial
{
public:
 const static long long fare = N * Factorial<N - 1>::fare;
};

template<>
class Factorial<1>
{
public:
 const static long long fare = 1;
};

// 一个比较难的,模板有int,也有类
template<int N>
class Line
{
public:
 const static long long fare = N;
};

template<int N>
class Square
{
public:
 const static long long fare = N * N;
};

template<int N>
class Cube
{
public:
 const static long long fare = N * N * N;
};

// 第一个参数是整形变量,第二个参数是模板类
template<int N, template<int N> class T>
class MyDefine
{
public:
 const static long long fare = MyDefine<N - 1, T>::fare + T<N>::fare;
};

template<template<int> class T>
class MyDefine<0, T> // 偏特化
{
public:
 const static long long fare = 0 + T<0>::fare;
};

void demo3()
{
    cout << MyAdd<10>::fare << endl;
    cout << MyPower<2, 10>::fare << endl;
    cout << Fib<91>::fare << endl; // long long类型在92时就会溢出,可以设为100,编译的时候会报错,这一点可以印证模板递归计算确实是发生在编译时期
    cout << Factorial<20>::fare << endl; // long long类型在21时就溢出了哦
    cout << MyDefine<2, Line>::fare << endl;
    cout << MyDefine<2, Square>::fare << endl;
    cout << MyDefine<2, Cube>::fare << endl;
}

/*
Type Traits
在STL中为了提供通用的操作而又不损失效率,我们用到了一种特殊的技巧,叫traits编程技巧。具体的来说,traits就是通过定义一些结构体或类,并利用模板类特化和偏特化的能力,给类型赋予一些特性,这些特性根据类型的不同而异。在程序设计中可以使用这些traits来判断一个类型的一些特性,引发C++的函数重载机制,实现同一种操作因类型不同而异的效果。traits的编程技巧极度弥补了C++语言的不足 。
Type traits are another term for being able to find out properties of a type at compile time.
The C++ Way
The following template determines if the template's argument type is a function:

This template relies on the SFINAE (Substitution Failure Is Not An Error) principle. Why it works is a fairly advanced template topic.
数组元素的类型不能为void类型、引用类型或函数类型。因此可构造一个测试用的成员函数模板,函数形参为模板参数的数组类型指针,这样数组元素就不能接受函数类型。同时提供该成员另一个重载版本,以应付T是函数类型的情况(SFINAE原则),对有干扰的void类型和引用类型提供特化以表示它们不是函数类型,这样就可以辨别T了。
代码中的U (*)[1]是一个指向数组U[1]的指针,U是数组元素的类型。可见这里的U不能为函数、引用及void类型。当U为函数、引用及void以外的其他类型时,sizeof就会使用这个版本的test函数,返回的Two的字节数2,则Yes为0,表示非函数类型。当为引用或void类型时,会使用特化版本,设置Yes为0。当为函数类型时,sizeof中的Test匹配有数组指针的那个Test时不会成功,但它能匹配另一个返回One为1个字节的test版本,根据SFINAE原则,它会使用这个版本的test,Yes设置为1。注意这里test只需声明,无需定义,因为sizeof并不会真正调用并执行该函数,不需要函数代码定义,它只是计算返回类型的字节数。
当然,我们还可以用其他的独特构造来实现,比如只有对函数类型,F&(指向函数类型的引用)才能转化为F*。通过判断能否把一个F&转化为F*,也可辨别出F是否是函数类型。
*/
template<typename T>
class IsFunctionT
{
private:
    typedef char One;
    typedef struct { char a[2]; } Two;
    template<typename U> static One test(...); // U为函数时使用这个,只需声明,无需定义
    template<typename U> static Two test(U (*)[1]); // U为非函数、非引用及非void类型时使用这个
public:
    enum { Yes = sizeof(test<T>(0)) == 1 }; // 记录测试的结果
    enum { No = !Yes };
};

template<typename T>
class IsFunctionT<T&> { // T是引用类型时会使用这个局部特化,表示它不是函数类型
public:
    enum { Yes = 0 };
    enum { No = !Yes };
};

template<>
class IsFunctionT<void> { // T是void类型时会使用这个全局特化,表示它不是函数类型
public:
    enum { Yes = 0 };
    enum { No = !Yes };
};

template<>
class IsFunctionT<void const> { // T是void const类型时会使用这个全局特化
public:
    enum { Yes = 0 };
    enum { No = !Yes };
};

// 对于void volatile和void const volatile类型也是一样
// ...

void demo4()
{
    typedef int (fp)(int);

    if (1 == IsFunctionT<fp>::Yes)
    {
        printf("fp is function");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值