`

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++ Templates The Complete Guide, 2nd Edition

    including variadic templates, generic lambdas, class template argument deduction, compile-time if, forwarding references, and user-defined literals. They also deeply delve into fundamental language ...

    C++ Templates The Complete Guide, 2nd Edition epub

    including variadic templates, generic lambdas, class template argument deduction, compile-time if, forwarding references, and user-defined literals. They also deeply delve into fundamental language ...

    C++ Templates The Complete Guide 2nd Edition

    including variadic templates, generic lambdas, class template argument deduction, compile-time if, forwarding references, and user-defined literals. They also deeply delve into fundamental language ...

    详解C++中十六进制字符串转数字(数值)

    详解C++中十六进制字符串转数字(数值) 主要有两个方法,其实都是对现有函数的使用:  方法1: sscanf()  函数名: sscanf 功 能: 从字符串格式化输入 用 法: int sscanf(char *string, char *format[,...

    c++编译时经常出现的错误

    c++编译时经常出现的错误,解决了初学者在编译过程遇到错误时一头雾水的问题

    Professional C++, 4th Edition

    this new fourth edition covers them all, including nested namespaces, structured bindings, string_view, template argument deduction for constructors, parallel algorithms, generalized sum algorithms, ...

    Argument 完美模板

    Argument 模板 完美,By András From Beijing Foreign Studies University

    GRE argument 模板

    gre 写作模板 之 argument 新东方小宝老师总结的模板

    Argument-dependent name lookup 参数依赖查找

    理解参数依赖查找! 加深对C++的理解! 我从这里开始理解ADL!

    C++程序中main(int argc, char *argv[])函数的参数意义

    在vs中编写C++程序时,可以往主函数里传递两个参数:main(int argc,char *argv[])。主函数不能被其它函数调用,在window操作系统下调用者是。 测试程序如下所示: #include stdafx.h #include iostream using ...

    Argument Parser for Modern C++.zip

    Argument Parser for Modern C++.zip

    c++ std::invalid_argument应用

    ),它的继承关系如下 exception——–&gt;logic_error———&gt;invalid_argument invalid_argument原型是 代码如下: class invalid_argument:public logic_error { public: explicit invalid_argument (const string& ...

    C++编程思想(第二卷)

    介绍C++的字符串、输入输出流、 STL算法、容器和模板的现代用法,包括模板元编程;解释多重继承问题的难点,展示RTTI的实际使用,描述了典型的设计模式及其实现,特别介绍被认为是标准C++下一版特征之一的多线程处理...

    C++实现的一个可以写递归lambda的Y函数

    最近学习C++11的variadic template argument,终于可以摆脱用fpmacro模板来复制一大堆代码的做法了,好开心。这个例子的main函数用lambda写了一个斐波那契数列的递归计算函数。跟以往不同的是,在Y函数的帮助下,这...

    242道ARGUMENT题目全分析

    ARGUMENT GRE ARGUMENT GRE ARGUMENT GRE ARGUMENT GRE ARGUMENT GRE ARGUMENT GRE ARGUMENT GRE ARGUMENT GRE ARGUMENT GRE

    深度探索模C++对象模型PDF

    参数的初始化(Argument Initialization) 返回值的初始化(Return Value Initialization) 在使用者层面做优化(Optimization at the user Level) 在编译器层面做优化(Optimization at the Compiler Level) Copy...

    深度探索C++对象模型 超清版

    参数的初始化(Argument Initialization) 返回值的初始化(Return Value Initialization) 在使用者层面做优化(Optimization at the user Level) 在编译器层面做优化(Optimization at the Compiler Level) Copy...

    简单粗暴写好argument

    简单粗暴写好Argument 模板提供 详细讲解

    Variable-length Argument Lists

    Variable-length Argument Lists

Global site tag (gtag.js) - Google Analytics