我理解为什么我们需要decltype(auto)
以及它与auto
的区别,但是我不知道为什么以及何时应该/需要使用decltype(expression)
。 在cppreference上的所有示例中,我可以只使用decltype(auto),我检查了它。 提前感谢你的帮助。
我能想到的最简单的例子是:
void foo(int i) {
for (decltype(i) j = 0; j < i; ++j)
...
}
在这里,索引j
自动具有与上限i
相同的类型。
lambda表达式提供了另一个示例:
[](auto i) {
for (decltype(i) j = 0; j < i; ++j)
...
}
但我无法知道为什么和何时应该/需要使用decltype(expression)
在C++11中,您可以使用尾随返回类型,但不能使用自动推导的返回类型。 例如:
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) { return t + u; }
C++14等价物为:
template<typename T, typename U>
decltype(auto) add(T t, U u) { return t + u; }
另一个用途是SFINAE,例如检测具有特定名称的成员函数的存在:
#include <iostream>
template<class T>
auto test_has_f(T* p) -> decltype(static_cast<void>(p->f()), std::true_type{}); // Cast to void to avoid user-defined operator,(), if any.
std::false_type test_has_f(void*);
template<class T>
using HasF = decltype(test_has_f(static_cast<T*>(0)));
struct A {};
struct B { void f(); };
int main() {
std::cout << HasF<A>::value << '\n'; // Outputs 0.
std::cout << HasF<B>::value << '\n'; // Outputs 1.
}
有时,您需要声明一个与另一个类型相关的类型,但又希望保持它的不可知论性:
struct foo
{
std::vector<int> data;
decltype(data)::iterator it;
};