• C++模板的偏特化与全特化(转)


    模板机制为C++提供了泛型编程的方式,在减少代码冗余的同时仍然可以提供类型安全。 特化必须在同一命名空间下进行,可以特化类模板也可以特化函数模板,但类模板可以偏特化和全特化,而函数模板只能全特化。 模板实例化时会优先匹配”模板参数”最相符的那个特化版本。

    模板的声明

    类模板和函数模板的声明方式是一样的,在类定义/模板定义之前声明模板参数列表。例如:

    // 类模板
    template <class T1, class T2>
    class A{
        T1 data1;
        T2 data2;
    };
    
    // 函数模板
    template <class T>
    T max(const T lhs, const T rhs){   
        return lhs > rhs ? lhs : rhs;
    }

    全特化

    通过全特化一个模板,可以对一个特定参数集合自定义当前模板,类模板和函数模板都可以全特化。 全特化的模板参数列表应当是空的,并且应当给出”模板实参”列表:

    // 全特化类模板
    template <>
    class A<int, double>{
        int data1;
        double data2;
    };
    
    // 函数模板
    template <>
    int max(const int lhs, const int rhs){   
        return lhs > rhs ? lhs : rhs;
    }

    注意类模板的全特化时在类名后给出了”模板实参”,但函数模板的函数名后没有给出”模板实参”。 这是因为编译器根据int max(const int, const int)的函数签名可以推导出来它是T max(const T, const T)的特化。

    特化的歧义

    上述函数模板不需指定”模板实参”是因为编译器可以通过函数签名来推导,但有时这一过程是有歧义的:

    template <class T>
    void f(){ T d; }
    
    template <>
    void f(){ int d; }

    此时编译器不知道f()是从f<T>()特化来的,编译时会有错误:

    error: no function template matches function template specialization 'f'

    这时我们便需要显式指定”模板实参”:

    template <class T>
    void f(){ T d; }
    
    template <>
    void f<int>(){ int d; }

    偏特化

    类似于全特化,偏特化也是为了给自定义一个参数集合的模板,但偏特化后的模板需要进一步的实例化才能形成确定的签名。 值得注意的是函数模板不允许偏特化,这一点在Effective C++: Item 25中有更详细的讨论。 偏特化也是以template来声明的,需要给出剩余的”模板形参”和必要的”模板实参”。例如:

    template <class T2>
    class A<int, T2>{
        ...
    };

    函数模板是不允许偏特化的,下面的声明会编译错:

    template <class T1, class T2>
    void f(){}
    
    template <class T2>
    void f<int, T2>(){}

    但函数允许重载,声明另一个函数模板即可替代偏特化的需要:

    template <class T2>
    void f(){}              // 注意:这里没有"模板实参"

    多数情况下函数模板重载就可以完成函数偏特化的需要,一个例外便是std命名空间。 std是一个特殊的命名空间,用户可以特化其中的模板,但不允许添加模板(其实任何内容都是禁止添加的)。 因此在std中添加重载函数是不允许的,在Effective C++: Item 25中给出了一个更详细的案例。

    转自:https://harttle.land/2015/10/03/cpp-template.html

  • 相关阅读:
    自调用匿名函数和js的Module模式
    设置一天中不同时段的倒计时,计算时针和分针的夹角
    移动端web开发中对点透的处理,以及理解fastclick如何做到去除300ms延迟
    使用Fiddler改变线上js文件的引用路径
    Linux下常用设置文件和文件夹读写权限操作
    RESTful API
    mysql之load语句
    Django学习之点赞功能
    Django学习之网站图标
    python学习之pyenv
  • 原文地址:https://www.cnblogs.com/zl1991/p/13136790.html
Copyright © 2020-2023  润新知