tags:
- Cpp
Type Deduction - Decltype in C++
decltype
也是在 C++11 引入的关键字,跟模板推导和 auto
类型推断的不同是:decltype
会准确地告诉你表达式所声明类型的实际类型。一般而言,decltype
推导出的类型和你预料中的所一致,它会保留表达式中的 CV qualifier、还可以帮你判断表达式到底是左值还是右值,它一律会帮你分析出来。
我们先用一些简单的例子来看看 decltype
是如何推导变量类型的:
int i = 10; // i is declared int type
decltype(i) j = 10; // j has the same type as i
const int ci = 10; // ci is declared const int
decltype(ci) cj = 10; // cj's type is const int
const int& cri = 10; // cri is declared const int&
decltype(cri) = 10; // thus the cri's type is const int&
std::vector<int> v(10) = {}; // v is declared std::vector<int>
v[0] = 0; // v[0] is int& (T& operatorp[](){})
是不是感觉简单明了,甚至比 auto
还简单?在实际应用上,decltype
用途最多的还是函数返回值推导。
在 auto
小节中,我们介绍了它的行为和函数模板很像,这就导致有时候它会说 auto
在推断函数返回值时忽略本应出现的引用,比方说:
template<typename Container, typename Index>
auto accessAndModify(Container& c, Index i) {
return c[i]; // should return a T&, right?
}
std::vector<int> v(10);
accessAndModify(v, 0) = 10; // error
一般而言,operator[]
都会返回 T&
类型,而在上面的情况中,auto
会将返回值推断为 T
,如果你对 auto
的推断规则不是很熟悉或者单纯忘记了,那这类错误就很容易出现。为了解决这个问题,要么在 auto
后面加上 &
,要么使用 decltype
进行更精细的类型推断,如:
// decltype in C++11
template<typename Container, typename Index>
auto accessAndModify(Container& c, Index i) -> decltype(c[i]) {
return c[i];
}
std::vector<int> v(10);
accessAndModify(v, 0) = 10;
这里,你会发现返回类型被放在了参数列表的后面,这种语法被称为返回类型后置 (trailing return type),这种语法尤其适合泛型编程:
template<typename T, typename U>
auto add(T a, U b) -> decltype(a + b) {
return a + b;
}
在 C++14,你还可以怎么写:
// decltype after C++14
template<typename Container, typename Index>
decltype(auto) accessAndModify(Container& c, Index i) {
return c[i];
}
std::vector<int> v(10);
accessAndModify(v, 0) = 10; // ok
decltype(auto)
是 C++14 引入的,它是 decltype
和 auto
的结合,它用于简化原先的表达(C++11 是需要在 decltype
中填入表达式,而 C++14 只需要填 auto
)。这里, auto
表示要推导的类型,而 decltype
表示在推导的过程中使用 decltype
的推导规则,即获取更精确的类型。
decltype(())
decltype
的类型推导已经能让我感觉到心满意足了,在最开始,我们说它“还可以帮你判断表达式到底是左值还是右值”。这就需要你对表达式做出一些修改:
int i = 0; // decltype(i) is int
// decltype((i)) is int&
decltype(auto) func() {
int i = 0;
return (i);
}
decltype((auto))
是非法的。