C++11 模板元编程 - 模板的类型参数


下面是我们熟悉的类模板的例子:一个简单的容器栈,它可以支持不同的类型做元素。

#include 
#include 

template
struct Stack
{
    void push(const T& elem)
    {
        elems.push_back(elem);
    }

    T pop()
    {
        if(empty()) throw std::out_of_range("Stack<>::pop: empty!");

        auto elem = elems.back();
        elems.pop_back();
        return elem;
    }

    bool empty() const
    {
        return elems.empty();
    }

private:
    std::vector elems;
};

它的用法如下:

Stack intStack;
intStack.push(-1);
intStack.push(2);
intStack.push(-3);
std::cout << intStack.pop() << std::endl;

Stack charStack;
charStack.push('A');
charStack.push('B');
std::cout << charStack.pop() << std::endl;

对于模板元编程,我们可以将类模板想象成一个编译期的函数,不同的是它的参数列表放在一对尖括号中。通过template struct Stack我们声明了一个编译期的函数,它的名字叫做Stack,它有一个类型形参T。

标准规定可以用typename或者class关键字指示模板形参是一个类型,不能使用struct。由于模板的类型形参不仅可以被替换为用户自定义类型,也可以被替换为内置类型(int, char, double...),所以使用typename语义上比class更清晰一些。本文统一使用typename。

如同把具体的实参传递给一个函数,函数就会计算求值一样,当我们把具体的类型当做实参传递给类模板时,类模板会在编译期进行计算,返回一个具体的类型。类模板的传参和函数类似,只不过语法上使用尖括号。

上例中我们分别将int和char当做实参,传递给类模板Stack。Stack得到实参后变成具体的类型StackStack。根据运行期C++的要求,只有具体类型才能产生对象,所以我们分别用StackStack生成了两个对象intStackcharStack

类模板的实现中可以继续使用类模板。上例中Stack的实现中使用了标准库中的类模板std::vector。一旦我们在Stack中用具体类型替换形参T,std::vector也会被传递参数从而变成一个具体类型,使得可以产生elems对象。

上面虽然我们用编译期函数来类比类模板,但是这时的类模板还远未达到模板元编程的要求,我们继续!


模板的默认参数

返回 C++11模板元编程 - 目录

你可能感兴趣的:(C++11 模板元编程 - 模板的类型参数)