C++什么时候应该用decltype

decltype通常应该被封装在通用(模板)库中,仅在完全必要的情况下使用。除此以外,非滥用的auto才是日常编程的语法糖。

1. 什么是decltype

decltype 的名称是由 “declare” 和 “type” 组合而来,表示它用于声明类型。

细节及用法请查阅《decltype 说明符》。简言之就是提取给予的表达式的类型,并且可以将该数据类型用于声明新变量。

2. 和auto的区别

看起来好像都能作为类型关键字声明变量,但是主要差别如下:

  1. auto声明的变量必须初始化,因为编译期就是以初始化的表达式进行类型推导的,因此也会在运行时计算表达式;而decltype 已经用表达式推导出类型了,就不必初始化,同时也不计算表达式的值。
  2. 对于修饰符的处理不同,比如const和引用等。不过由于C++不断打补丁的缘故,存在一些特例增加了复杂性,此处不展开。

以上仅为粗浅的差异介绍,decltype常见于模板编程中,比如《c++ 11 既然有auto了,为什么又要有decltype呢?》中xinnjie实现的编译期检测一个类是否包含一个 foo() 方法的例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
//c++14
#include <experimental/type_traits> // for srd::experimental::is_de_detected
#include <iostream>
#include <type_traits>
template<typename T>
using has_foo_func = decltype(std::declval<T>().foo());

struct HasFoo {
    void foo() {}
};

struct NotHasFoo {
};

int main() {
    std::cout << "has foo" << std::experimental::is_detected<has_foo_func, HasFoo>::value << std::endl; // true
    std::cout << "has foo" << std::experimental::is_detected<has_foo_func, NotHasFoo>::value << std::endl; // false
}

B. Stroustrup在《C++11 FAQ》中介绍了更多例子。

如果非要觉得autodecltype功能重复,我认为是的。如《简述C++11中auto和decltype》中所说:

decltype的出现是为了解决auto存在的一些问题,能用auto一定可以用decltype。但是auto相比decltype又更加简洁,所以能用auto就使用auto,不行就用decltype。

部分情况下,decltype 会是更好的选择。比如当您希望 y 始终具有 x 声明的类型时。

When you want y to always have whatever the declared type of x is.

3. 总结

You shouldn’t be seeing or using decltype in “day-to-day” programming. It is most useful in generic (templated) library code, where the expression in question is not known and depends on a paramater. (By contrast, auto may be used generously all over the place.) In short, if you’re new to programming, you probably won’t need to use decltype for some time.

如《What is decltype and how is it used?》中提到的一个观点:您不应该在“日常”编程中看到或使用 decltype 。它在通用(模板化)库代码中最有用,其中所讨论的表达式未知并且取决于参数。 (相比之下, auto 可能在任何地方都被广泛使用。)简而言之,如果您是编程新手,您可能在一段时间内不需要使用 decltype

引用