引入或不引入临时性,重要吗?
如果您查看使用函数结果的表达式,这会更有意义:
// given
template<typename T> struct Foo {};
template<typename T> Foo<T> foo();
template<typename T> void bar(const Foo<T>&);
// This:
bar(foo<int>());
// Is equivalent to:
{
Foo<int>&& tmp = foo<int>();
bar(tmp);
}
// So should tmp "exist" here?
using T = decltype(foo<int>());
您很容易争辩说foo<int>() 表达式实际上等价于 到Foo<int>&& tmp = foo<int>()。如果tmp 的存在在某种decltype() 上下文中是不可取的,那么需要明确说明。
tmp 在这里绝对是不可取的。它会导致创建 Foo<int> 特化。但仅仅因为你已经确定了一个类型并不意味着你实际上正在使用它。类型别名也是如此。
演示:(参见godbolt)
#include <type_traits>
template<typename T>
struct Foo {
// Will cause a compile error if it's ever instantiated with int
static_assert(!std::is_same_v<T, int>);
};
using FooInt = Foo<int>;
template<typename T>
Foo<T> foo() {
return {};
}
void bar() {
// Does not cause Foo<int> to exist just yet
using T = decltype(foo<int>());
// This instantiates Foo<int> and causes the compile error
// T x;
}
区别对待它们的理由是什么?
注意以下内容更多地是关于如何推理的指南。实际的技术细节有所不同,但可能会相当复杂。
不要认为括号有什么特别之处。相反,将其视为decltype(id-expression) 是一种特殊情况。
假设我们有以下声明:int x;
x 表达式的行为不像 int,而是 int&。否则x = 3; 没有意义。
尽管如此,decltype(x) 仍然是 int。这是特例:decltype(id-expression) 返回标识符本身的类型,而不是表达式的类型。
另一方面,(x) 的行为也类似于 int&,但由于它不是 id-expression,因此它被解释为任何正则表达式。所以decltype((x)) 是int&。
#include <type_traits>
int x = 0;
using T = decltype(x);
using U = decltype((x));
static_assert(std::is_same_v<T, int>);
static_assert(std::is_same_v<U, int&>);