模板函数返回类型推断
Ruichen Ni
需求来源
以矩阵数学库举例
// Matrix.h
#include <vector>
template<typename T>
class Matrix
{
public:
//!> Constructor and Deconstructor
Matrix() = default;
~Matrix() = default;
//!> Add operator
Matrix<T> operator+(const Matrix<T>& m) const
{
Matrix<T> result;
//!> Skip the size length check!
for (int i = 0; i < data.size(); i++)
result.data.push_back(data[i] + m.data[i]);
return result;
}
public: //!< Should be private for data encapsulation. Here is just for explanation
std::vector<T> data;
};
// main.cc
#include "Matrix.h"
int main()
{
Matrix<int> i_matrix;
i_matrix.data = {1, 2, 3};
Matrix<double> d_matrix;
d_matrix.data = {4.0, 5.0, 6.0};
return 0;
}
现在希望执行矩阵的加法操作,i_matrix + i_matrix
和d_matrix + d_matrix
都可以通过调用已有的Matrix<T>::operator+()
函数实现。但是如果我想执行i_matrix + d_matrix
就会出现报错
error C2679: 二元"+": 没有找到接受“Matrix
”类型的右操作数的运算符(或没有可接受的转换)
类型推断 (decltype)
关于对decltype
的介绍转载自CSDN博客。
C++引入关键字decltype的核心功能,用于根据表达式推导出变量的类型;当使用decltype(e) 推导表达式 e(类型为T)的类型时,C++11标准定义decltype的推导规则如下:
- 如果是一个未加括号的标识符表达式或类成员访问,那么decltype(e)的推导结果为e类型T;假如不存在这样的实体或e是一组重载函数,那么decltype(e)无法推导。而且推导过程const/volatile 限定符会被忽略;
- 如果e是一个可调用对象,那么decltype(e)推导为可调用对象返回值的类型;
- 如果e是一个左值,decltype(e)推导为T&。const/volatile 限定符不能忽略;
- 如果e是一个将亡值,decltype(e)推导为T&&,const/volatile 限定符不可忽略;
- 如decltype(e)无法命中上述4情况,decltype(e)将会推导为e的类型T;
为了让大家更形象的理解这5条规则,下面我们通过一些示例来说明这五条推导规则。
示例
Example 1: 未加括号标识符表达式
int x = 42;
decltype(x) y; // 推导结果是 int,满足第1条规则
Example 2: 加括号的标识符表达式
int x = 42;
decltype((x)) y = x; // 推导结果是 int&,满足第三条规则
Example 3: 未加括号的类成员访问
struct MyClass {
int member;
};
const MyClass obj;
decltype(obj.member) result = obj.member; // 推导结果是 int, 忽略const/volatile 限定符,满足第1条规则
Example 4: 加括号的类成员访问
struct MyClass {
int member;
};
const MyClass obj;
decltype((bj.member)) result = obj.member; // 推导结果是 const int&, const/volatile 限定符不能忽略,满足第3条规则
Example 5: 可调用对象表达式
int add(int a, int b)
{
return a + b;
}
decltype(add(1, 2)) result; // 推导结果是 int,满足第2条规则
Example 6: 将亡值
int x = 42;
decltype(std::move(x)) result = std::move(x); // 推导结果为int&&,std::move(x) 为将亡值
Example 7: 右值表达式
int x = 42;
decltype(x + 1) result; // 推导结果是 int(右值表达式 x + 1 的类型是 int)
Example 8: 右值引用变量
int&& i = 500;
decltype(i) x2; // x2的类型是int&&,满足第5条
模板函数返回值推断
将Matrix
类定义中的模板函数修改为
// Matrix.h
#include <vector>
template<typename T>
class Matrix
{
public:
//!> Constructor and Deconstructor
Matrix() = default;
~Matrix() = default;
//!> Add operator
template<typename U>
auto operator+(const Matrix<U>& m) const -> Matrix<decltype(T() + U())>
{
Matrix<decltype(T() + U())> result;
//!> Skip the size length check!
for (int i = 0; i < data.size(); i++)
result.data.push_back(data[i] + m.data[i]);
return result;
}
public: //!< Should be private for data encapsulation. Here is just for explanation
std::vector<T> data;
};
就能够支持进行i_matrix + d_matrix
的操作。