C++模板编程(24)---模板自变量推导Template Argument Deduction

如果在每一个function template调用语句中明确指定template argument,例如,

concat<std::string, int>(s,3), 程序代码会显得笨拙又难看。幸运的是C++编译器通常可以自动判定你所需要的template argument类型,这是透过要给名为template argument deduction模板自变量推导的强大机制完成的。

本文详细解说template argument deduction的细节。很多推导规则所产生的结果都符合人们的直观认知。

1. 推导过程Dedcution Process,

    编译器会比对调用语句内某自变量的类型和function template内对应的参数化类型,并试图总结出被推导的一个或多个参数的正确替代物。每一对自变量-参数独立分析。如果推导结束时结果有异常,则推导失败。考虑下面例子:

template <typename T>

T const& max(T const& a, T const& b)

{

        return a< b? b: a;

}

int g = max(1, 1.0);

在这里,第一个call argument类型为int,因此max()的template parameter T被暂时推导为int。然而第二个call argument的类型为double,因此T应该为double:这与第一个推导结果冲突。注意是推导失败,不是程序非法:推导程序还是有可能成功找到另一个名为max的template(因为function template可以重载,就像常规functions那样)。

    即使所有的template parameters推导结果前后一致,但如果以自变量替换进去后导致函数声明的其余部分变为非法,推导过程还是有可能失败。例如:

template <typename T>

typename T::ElementT at(T const& a , int i)

{

        return a[i];

}

void f(int* p)

{

        int x= at(p,7);

}

在这里T被推断为int*(T只在一个参数类型中出现,因此显然不会发生冲突)。然而,将返回类型T ::ElementT中的T替换为int* 显然是非法的,因此推导失败。

    我们探究自变量-参数匹配是如何进行的。今后的描述将出现符号A和P,意义如下:

将类型A(由argument type导出)匹配至一个参数化类型P(有template parameter的声明导出); 

如果参数被声明为以by reference 方式传递,则P表示被指涉reference类型,A为自变量类型;

否则P表示声明之参数类型,A是个由array或function退化而成并去除外围之const 和volatile饰词的pointer类型。例如:

template <typename T> void f(T);   //P 为T

template <typename T> void g(T&); //P 仍为T

double x[20];

int const seven = 7;

f(x);   //nonreferec parameter, T 为 double*

g(x); // reference parameter, T 为double[20]

f(seven); //nonreference parameter: T为 int

g(seven);  //reference parameter: T 为int const

f(7); //nonreference parameter: T 为int

g(7); //reference paramter: T int =>错误,不能把7当作int& 传递

    对于调用语句f(x),x由array类型退化为double*类型,T被推导为该类型。调用语句f(seven)中,const饰词被卸除,从而T被推导为int。

    调用语句g(x)中,T被推导为double【20】(并没有发生类型退化);

类似情况,g(seven)的自变量是一个int const类型的左值lvalue,此外,由于const和volatile饰词在匹配reference paramters 时不被卸除,因此T被推导为 int const。

   然而g(7)中T被推导为int(因为nonclass rvalue表达式不能含有带const或volatile饰词的类型),因此调用失败,因此自变量7不能传给一个int&类型的参数。

    当字符串字面常量string literal类型的自变量被绑定到reference parameter时,不会发生退化。重新考虑先前的max()template:

   template <typename T>

   T const& max(T const & a, T const& b);

 很多人希望在max("Apple", "Pear");表达式中,T被推导为 const char*,然而,“Apple”的类型却是char const【6】,“Pear”的类型式char const【5】。array类型至pointer类型的退化过程并未发生(因为max的参数使用by reference传递方式),因此如果推导成功,T必须又是char【6】又是char【5】,那当然不可能。

2.推导之前后脉络Deduced Contexts

比T更复杂的参数化类型也可以被匹配到一个给定的自变量类型上。下面是一些基本例子:

template <typename T>

void f1(T*);

template <typename E, int N>

void f2(E (&) [N]);

template <typename T1, typename T2, typenam T3>

void f3(T1 (T2::*)(T3*)); //f3的参数是pointer-to-member type

                             //f3的参数是个T2成员函数,该函数的返回类型为T1,接受一个T3*参数

class S {

public:

        void f(double *);

};

void g(int *** ppp)

{

        bool b[42];

        f1(ppp);    // 推导结果:T为  int**

        f2(b);       //   推导结果:E  为 bool, N=42

        f3(&S::f);    //  推导结果:T1=void, T2=S, T3=double

}

3.特殊推导情境Special Decution Situations

4. 可接受的自变量转型Allowable Argument Convertion

5. 类模板参数Class Template Parameters

6.默认的调用自变量Default Call Arguments

7. 受限模板扩展技术restricted template expansion

8. 小结 Summary

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
模板参数推导template argument deduction)是C++11中引入的一个新特性,它可以自动推导模板参数,避免手动指定模板参数。 在使用模板函数或模板类时,通常需要手动指定模板参数,例如: ``` template<typename T> void foo(T t); int main() { foo<int>(1); // 指定模板参数为int return 0; } ``` 在上面的代码中,我们调用了模板函数`foo`,并手动指定了模板参数为int。这种方式比较繁琐,容易出错。 模板参数推导可以自动推导模板参数,避免手动指定模板参数。例如: ``` template<typename T> void foo(T t); int main() { foo(1); // 自动推导模板参数为int return 0; } ``` 在上面的代码中,我们调用了模板函数`foo`,并没有手动指定模板参数,编译器会自动推导模板参数为int。 模板参数推导可以用于函数模板和类模板的实例化过程中。它可以根据函数参数或对象成员的类型,自动推导模板参数的类型。例如: ``` template<typename T, int N> class Array { public: T data[N]; }; int main() { Array arr{1, 2, 3}; // 自动推导模板参数为int和3 return 0; } ``` 在上面的代码中,我们定义了一个类模板`Array`,它有两个模板参数,一个是类型参数T,一个是整型参数N。在实例化`Array`对象时,我们只传入了一个参数{1, 2, 3},编译器会自动推导模板参数为int和3。 需要注意的是,模板参数推导只能用于函数模板和类模板的实例化过程中,不能用于模板定义中。在模板定义中,必须手动指定模板参数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值