模板函数——后置返回值类型(trailing return type)

       后置返回值类型主要用于模板函数中,它是C++11推出的新用法。其中使用到了auto和decltype两种类型说明符。

       auto和decltype虽然都是类型说明符,但是二者是不同的:auto是根据推导初始值的类型来确定变量的类型,而decltype则只是确定类型,如下所示:

auto i = x + y;   //通过x+y的结果类型来推导出i的类型并对其初始化

decltype(x+y) i;    //通过x+y的结果类型来定义i的类型

       下面就来说一下后置返回值类型。

      现在写一个模板函数add:传入两个任意类型参数,返回两数之和。如果使用模板的话,大概可以写成这样:

template
XXX add(T v1, Y v2)
{
    return v1+v2;
}

      那么,这里的返回值应当是什么类型呢?如果传入的两个参数类型不同,那么情况也是不同的:如果一个是int,一个是double,那么返回值就是double;如果一个是int,一个是short,那么返回值就是int;如果一个是char,一个是short,返回值则是int。可见,返回值类型是与v1+v2这一结果的类型相关的。

       那么,可否直接把返回值也写成模板呢?如下所示:

template
R add(T v1, Y v2)
{
    return v1+v2;
}

       这样显然是不行的,因为你调用add函数的时候只是传入了两个参数,而这里的模板参数有3个,显然R模板参数是无法推导的,编译器也会报错。

       由于返回值类型是靠v1+v2这一结果得到的,因此就可以考虑使用前面所说的decltype,就像这样:

template
decltype(v1+v2) add(T v1, Y v2)
{
    return v1+v2;
}

        不过由于这里的函数是返回值前置类型,而在推导decltype(v1+v2)时v1和v2还未定义,因此就会报错“未使模板专有化”。

        可以看到,这里的问题主要是因为返回值类型是前置的,为了解决这个问题,C++11就引入了返回值类型后置,这就相当于把上面的decltype(v1+v2)放到形参v1和v2的声明后面去,这样一来,再使用decltype的时候v1和v2就已经声明了类型,自然也就可以推导了,不过在语法上就需要用到auto了:

template
auto add(T v1, Y v2) -> decltype(v1 + v2)
{
	return v1 + v2;
}

       这样,就可以根据传入的参数类型来推导返回值类型了。

       后置返回值类型是auto+decltype的应用,实际上,你也可以不用decltype,就像auto add(T v1, Y v2) -> int;这样也是完全可以的,不过返回值类型既然都已经确定了,后置返回值类型又有什么必要呢?

       

 

       当然,你也完全可以不用后置返回值类型去解决这个问题:既然v1和v2还没声明,那么就直接用模板类型T和Y去构造两个对象,然后用构造的对象求和再decltype去推导就行了。不过由于T和Y类型不一定都有构造函数,因此可以直接先把一个常数强制转换为一个T/Y类型的指针,然后再对这个指针解引,得到的自然就是T和Y类型的实例了:

template
decltype(*(T*)0, *(Y*)0 ) add(T v1, Y v2)   //可以用0,也可以用任意常数
{
    return v1+v2;
}

 

你可能感兴趣的:(C/C++)