模板参数推导

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模板参数推导相关的知识,希望对你有一定的参考价值。

STL有6大组件,阅读《STL源码剖析》后,对于我来说主要收货为:内存分配器、迭代器、仿函数。特别是迭代器章节收货最多,其中重中之重为traits机制的运用。

 

traits技法——STL的入门钥匙

 

首先必须清楚模板的参数推导机制,例如:

template < typename I>
inline void test(I iter)
{
    *iter tmp; //假设希望定义一个临时变量,类型为iter指针所指之物的类型(这里当然编译不过去)
}
//在这里我们无法知道 *iter是什么类型,假设需要定义*iter类型的变量,就需要使用参数推导机制:
template < typename J>
inline void test_impl(J v)
{
    J tmp = v; //编译通过
}
template < typename I>
inline void test(I iter)
{
    test_impl(*iter); //模板的参数推导机制将能在编译时推导出*iter的类型。
}
 
//但是这种思想无法运用到函数的返回值上,因为模板只有参数推导功能,没有返回值的推导。为此STL引入了traits(萃取):

template < typename I>
struct my_type_traits
{
    //定义内嵌类型:
    typedef typename I::value_type value_type;
}
//再像这样定义一个函数:
template < typename I>
typename my_type_traits<I>::value_type test_ret(I i)
{
  return *i;
}
//但是前提是每个类型I都必须有自己的内嵌类型value_type,再使用时我们这样:
template < typename T>
class T1
{
public:
    void set_value(T1 v)
    {
        m_v = v;
    }
    typedef T value_type; //这个必须有
    private:
    T m_v;
}
 
int main()
{
    T1 t;
    t.set_value(100);
    int n = test_ret(t); //n=100;如果换成char或者其他自定义类型也一样通用
}
//可以看出上面的例子中 test_ret的参数必须要有内嵌类型value_type,假如没有的话,那么就会出现:
int main()
{
    int n = 0;
    int v = test_ret(&n); //编译将报错
}
 
//STL使用偏特化来解决这个问题,再定义一个萃取结构:
template < typename I>
struct my_type_traits
{
    //定义内嵌类型:
    typedef typename I value_type;
}
//使用内嵌类型示例:
int main()
{
    int n = 0;
    int v = test_ret(&n); //编译正确
}

 

以上是关于模板参数推导的主要内容,如果未能解决你的问题,请参考以下文章

C++ 模板参数推导/替换失败:

带有函数指针和引用的模板参数推导[重复]

用右值/左值理解模板参数推导

C++ 中聚合的带括号初始化的模板参数推导

C++0x 右值引用模板参数推导

模板参数推导