`

C++模板参数推导(template argument deduction)【转】

 
阅读更多

1 模板参数推导在迭代器中的使用

在算法中运用迭代器时,可能会用到其相应类型(associative type),即迭代器所指向对象的类别。但C++只支持sizeof(),并不存在typeof()之说(即使运用RTTI性质中的typeid()获得的也只是类型名称不能用来做变量声明之用)。
为解决此问题,可以利用函数模板(function template)的参数推导(argument deduction)机制:

 

template <class I, class T>
void fun_impl(I iter, T t){     // 此处该函数利用模板参数推导得知T为*iter类型
    T tmp;                      // 可以声明变量
    //...
};

template <class I>
inline void fun(I iter){
    fun_impl(iter, *iter); //此处把*iter作为第二个参数传递给fun_impl()
}
int main(int argc, char *argv[])
{
    int i;
    fun(&i);
    return 0;
}

再例如:

 

template<class I, class Cmp>  
void insertSort(const I& begin, const I& end, Cmp lessThan);  
  
template <class I, class T>  
void _insertSort(const I& begin, const I& end, const T t);  
  
template<class I, class T, class Cmp>  
void _insertSort(const I& begin, const I& end, Cmp lessThan, const T& t);  
  
template <class I>  
void insertSort(const I& begin, const I& end){  
    if(begin != end)  
        _insertSort(begin, end, *begin); // 把*begin传递做为第三个参数
}  
  
template <class I, class T>  
// 此时__insertSort利用模板参数推导机制推测出T的类型,其实就是上个函数insertSort(const I& begin, const I& end)中迭代器begin所指向对象的类型
void _insertSort(const I& begin, const I& end, const T t){ 
    insertSort(begin, end, less<T>());                     //此时T已被推测出来可以直接使用
}  

template<class I, class Cmp>  
void insertSort(const I& begin, const I& end, Cmp lessThan){  
    if(begin != end)  
        _insertSort(begin, end, lessThan, *begin);
}  
  
//算法的具体实现  
template<class I, class T, class Cmp>  
void _insertSort(const I& begin, const I& end, Cmp lessThan, const T& t){  
    I j;  
    for(I i = begin+1; i != end; ++i){  
        T tmp = *i; //通过参数推导确定T类型  
        for(j = i; j != begin && lessThan(tmp, *(j-1)); --j)  
            *j = *(j-1);  
        *j = tmp;  
    }  
}

参数为两个迭代器的函数insertSort把其中一个迭代器解引用后传递给参数为两个迭代器和一个迭代器指向对象类型的三个参数的__insertSort函数,用户并不关心底层如何实现,只需要传递两个参数即可,并未告知函数迭代器指向对象的类型但可以通过模板参数推导机制来推测,从而方便用户。

2 模板参数引用与非引用的区别

当模板参数是非引用时会导致模板参数推断衰减(decaying)(把数组和函数类型变成指针类型、去掉const, volatile等修饰符)。
例如:

 

template<typename T> void f(T);    //PisT 

template<typename T> void g(T&);  // P is also T 

double x[20]; 

int const seven = 7; 

f(x);      // nonreference parameter: T is double* 
g(x);      // reference parameter:    T is double[20] 
f(seven);  // nonreference parameter: T is int 
g(seven);  // reference parameter:    T is int const 
f(7);      // nonreference parameter: T is int 
g(7);      // reference parameter:    T is int => ERROR: can't pass 7 to int& 

f是非引用模板参数,所以会decaying 把double[]变成double*,同理int const => int,最后一个传递是非法的,因为不能把常数作为int&。


再例如:

 

#include <iostream>
#include <typeinfo>
using namespace std;

template <typename T>
inline const T& Max(const T& a, const T& b){
    return a<b?b:a;
}

template <typename T>
inline T MMax(T a, T b){
    return a<b?b:a;
}

template <typename T>
void ref(const T& t){
    cout<<"Ref: "<<typeid(t).name()<<endl;
}

template <typename T>
void nonref(T t){
    cout<<"Nonref: "<<typeid(t).name()<<endl;
}

int main(int argc, char *argv[])
{
    ref("hello");               // const char [6]
    nonref("hello");            // const char *
    Max("abcd", "cdef");        // 都是const char [4]类型
    // Max("abc", "abcde");     //error 前者const char [3],后者const char [5],不一致,所以出错。
    MMax("abc", "abcde");       // 都是const char *类型,匹配所以可以运行
    Max(1, 1.1);
    return 0;
}

Author: visayafan <visayafan@gmail.com>

Date: 2011-11-29 21:02:01

HTML generated by org-mode 6.33x in emacs 23

分享到:
评论

相关推荐

    C++模板中文版及源代码

    - `explicit template argument deduction`(显式模板参数推导)可以解决这些问题,如`f(x)`。 6. **SFINAE原则**: - SFINAE(Substitution Failure Is Not An Error)是C++模板设计的一个基本原则。 - 如果在...

    C++ TEMPLATE

    9. **模板参数推导(Template Argument Deduction)**: 在调用模板函数或使用模板类时,编译器会尝试自动推断模板参数。例如,在 `max(3, 5)` 中,编译器可以推断出 `T` 应为 `int` 类型。 10. **C++11 引入的...

    C++ Templates(侯捷版1-10章).pdf

    - **模板参数推导(Template Argument Deduction)**:编译器如何根据函数调用自动确定模板参数的过程。 - **模板重载解析(Template Overload Resolution)**:当存在多个模板候选时,编译器如何选择最佳匹配的过程。 -...

    C++Templates_c++templates_C++Templates全览_healthbhr_源码.rar

    - **模板推断(Template Argument Deduction for Constructors)**:C++17引入的构造函数模板推断,使得初始化更简洁。 通过深入学习《C++ Templates》这本书,读者不仅可以掌握模板的基本概念,还能了解到模板在...

    C++Templates(中文版)

    - **Template Argument Deduction**:自动推导模板参数类型的过程。 - **Template Overload Resolution**:解决模板函数重载时的选择问题。 - **Looking Up Names in Templates**:在模板上下文中查找标识符的规则。...

    c++2020协议规范

    C++20引入了模板参数推导指引(Template Argument Deduction for Class Templates),使得类模板的构造函数可以像函数模板一样进行参数推导,简化了模板类的使用。 七、 spaceship operator () spaceship operator...

    C++ 17 标准手册_C++_

    5. **类模板的自动推导(Class Template Argument Deduction, CTAD)** 类模板实例化的参数可以自动推导,比如在创建`std::vector`或`std::map`时,可以省略模板参数,编译器会自动推断出类型。 6. **内联变量...

    c++20的编程示例和深入解析

    C++20添加了模板参数推导(Template Argument Deduction for Class Templates),使得`auto`可以用于类模板实例化,类似于函数模板的推导规则。 9. **数学函数**: 标准库新增了对浮点数的许多数学函数,如`std::...

    数据结构与算法分析--C++描述(第3版)

    - **Template Argument Deduction(模板参数推导)**: 编译器自动推断模板参数的过程,简化了模板函数或类的调用。 - **Template Overload Resolution(模板重载解析)**: 编译器确定哪个模板函数或类的实例应该被...

    C++11/17/20 标准帮助文档(docsets 格式)

    5. **类模板的自动推导(Class Template Argument Deduction)**:如`std::vector vec = {1, 2, 3};`。 6. **折叠表达式(Fold Expressions)**:使模板元编程更简洁。 C++20: C++20是最新标准,带来了更多革新:...

    cppreference.rar

    6. 增强的模板推理(Template Argument Deduction for Class Templates):C++17对模板类的参数推断进行了增强,使得模板类的使用更加方便。 7. 标准库中的字符串视图(std::string_view):这是一种轻量级的字符串...

    cpp-简单的可扩展的只包括头文件的C17参数解析器

    C++17是C++语言的一个重要版本,引入了许多新特性,如std::optional、std::variant、模板推导指引(Template Argument Deduction Guides)等,这些都可能被这个参数解析器所利用,以提供更简洁、高效的代码。...

    MinGW64 GCC 8.1

    4. **类模板的参数推导(Class Template Argument Deduction,CTAD)**:在创建模板类的对象时,编译器能自动推断模板参数,简化了代码,如`std::vector v{1, 2, 3};`。 5. **结构化绑定**:允许一次性解构复杂类型...

Global site tag (gtag.js) - Google Analytics