c++ 什么时候应该使用decltype(x)而不是auto来声明变量的类型?

y3bcpkx1  于 2023-10-21  发布在  其他
关注(0)|答案(6)|浏览(140)

我看到decltype(x)在宏中使用,其中x是一个变量名,因为宏中不知道对象的类型。
举例来说:

decltype(x) y = expr;

我可以很容易地使用auto而不是decltype。那么,在哪些情况下,变量类型声明需要decltype而不是auto呢?

sxpgvts3

sxpgvts31#

decltype在你需要返回一些未知类型时变得很方便,这些类型在编译过程中被评估:

template<class A, class B>
void MultiplyAB(A a, B b, decltype(a*b)& output)
{
    output = a * b;
}

此外,如果你不喜欢引用处理输出的方式,那么你也可以使用后来指定的返回类型(也可以使用decltype):

template<class A, class B>
auto MultiplyAB(A a, B b) -> decltype(a*b)
{
    return a * b;
}

所有这一切,以及更多,都是由B描述的。在C++ FAQ中的Stroustrup。

wko9yo5t

wko9yo5t2#

y的类型为:

  • expr类型不同(或可能不同)。如果是相同的,那么auto将更简洁。
  • 类似地,对于auto &auto可以表达的expr类型的其它修改。

以及以下之一:

  • 依赖于周围代码中的某些内容(即,并不总是相同的类型),并且很难使用类型特征或类似的方法来编写。这种情况往往发生在模板代码中。可能有一个类型trait,您可以使用它从模板参数中获取所需的类型,但也可能没有,因此使用decltype可以保存您定义的类型。
  • 总是相同的类型,(或者以一种易于使用现有类型traits或类似方式表达的方式依赖于模板参数),但是类型编写起来非常冗长,并且可以使用更短和更清晰的表达式。

因此,例如,用decltype(*it)替换std::iterator_traits<RandomAccessIterator>::value_type可能是一种成功,尽管auto经常处理这种情况。
主观判断是在“什么是困难的”、“什么是冗长的”和“什么是清楚的”这一点上作出的,但无论你在具体案件中如何作出这些判断,程序规则都是一样的。

k2arahey

k2arahey3#

当您希望y始终具有x的声明类型时。

jogvjijk

jogvjijk4#

根据你的问题,

  • 当你想要一个新变量与原始变量的类型**完全相同时,你应该使用decltype
  • 当你想把某个表达式的值给一个新变量,并且你想或需要推导出它的类型时,你应该使用auto

decltype(x) y总是使用与x声明的类型完全相同的类型声明y。特别是:

  • 如果x的类型为const int,则y的类型为const int
  • 如果x的类型为int[100],则y的类型为int[100]
  • 如果x的类型为int f(int),则y的类型为int f(int)。是的,这实际上声明了另一个 * 函数 *,其类型与原始函数相同。
  • 如果x的类型为int&,则y的类型为int&;如果x的类型为int&&,则y的类型为int&&

x具有以下类型时,auto y = x将使用以下类型声明y

  • 如果x的类型为const int,则y的类型为int。也就是说,auto去掉顶级cv限定符。
  • 如果x的类型为int[100],则y的类型为int*。也就是说,auto执行数组到指针的转换。[1]第一章
  • 如果x的类型为int f(int),则y的类型为int (*)(int)。也就是说,auto执行函数到函数指针的转换。[二]《中国日报》
  • 最后,如果x的类型为int&int&&,则y的类型为int。也就是说,auto删除引用

[1]这里不能使用decltype,因为不能复制初始化数组。
[2]这里不能使用decltype,因为不能初始化函数。
[3]auto去掉引用的原因是C++没有引用类型的表达式!一旦初始化,引用的“引用性”就变得不可见。
请注意,当decltype的参数不是id表达式时,decltype也会做一些完全不同的事情,我不会在这里讨论。

z4bn682m

z4bn682m5#

当你的变量类型与被计算的表达式无关时。
例如:

struct Bar
{
    Bar(int) {} // implicitly constructable
}

struct Bar2
{
    Bar2(int) {} // implicitly constructable
}

struct Foo
{
    static Bar var;
}

struct Foo2
{
    static Bar2 var;
}

template <typename T>
void dummy()
{
    decltype(T::var) myVar = 42;
}

dummy<Foo>(); // myVar is of type Bar1
dummy<Foo2>(); // myVar is of type Bar2
auto myAutoVar = 42; // type is int

当然,这只是一个用例,还有更多。

hmtdttj4

hmtdttj46#

decltypeauto的通用性要高得多,并且可以随时替代它。因此,我认为decltype应该只在完全必要的情况下使用,所以如果auto产生错误的结果,你应该使用decltype。此外,你还不能在返回类型和参数中使用auto,所以你也可以在那里使用decltype。C14将显著增加auto的潜在用途,我猜C17将更进一步。因此,只有当您需要更改expr的结果类型时,才需要使用decltype
另一件需要考虑的事情是,decltype并不是真正必要的,除非你正在编写库代码,auto对于日常编程来说是很好的,如果你想让你的代码更简洁,尽可能多地使用auto是否好还有待讨论,但是当处理像paddas这样的不可描述的类型时,它实际上是必要的。

相关问题