我何时应该使用decltype(x)而不是auto来声明变量的类型?

时间:2014-01-26 21:00:35

标签: c++ c++11

我看到decltype(x)在宏中使用,其中x是变量名,因为在宏内部不知道对象的类型。

例如:

decltype(x) y = expr;

我可以轻松使用auto代替decltype。那么,变量类型声明而不是decltype需要auto的情况是什么?

6 个答案:

答案 0 :(得分:18)

当所需的y类型为:

时,您应该使用它
  • expr的类型不同(或可能不同)。如果它是相同的那么auto会更简洁。
  • 同样适用于auto &expr可以表达的auto类型的其他修改。

以及以下之一:

  • 依赖于周围代码中的某些内容(即并不总是相同类型),并且难以使用类型特征或类似内容进行编写。这将倾向于在模板代码中发生。可能有一个类型特征可用于从模板参数中获取所需类型,但是可能不会再使用decltype来保存您定义的类型。
  • 总是相同的类型,(或者以一种易于使用现有类型特征或类似方式表达的方式依赖于模板参数)但类型是非常冗长的写入,并且有一个更短更清晰的表达式,你可以改用。

因此,例如,将std::iterator_traits<RandomAccessIterator>::value_type替换为decltype(*it)可能会获胜,但auto通常会处理此类情况。

主观判断进入“困难”,“什么是啰嗦”和“什么是明确”这一点,但无论你如何在特定情况下做出判断,程序规则都可以相同。

答案 1 :(得分:17)

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

答案 2 :(得分:17)

当你需要返回一些在编译期间评估的未知类型时,

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. Stroustrup在C++ FAQ中描述。

答案 3 :(得分:8)

在您的问题中,

  • 如果您想要一个与原始变量具有完全相同类型的新变量,则应使用decltype

  • 如果您希望将某个表达式的值分配给新变量,并且您希望或需要推断其类型,则应使用auto

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

  • 如果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&&
auto y = x具有以下类型时,

y会使用以下类型声明x

  • 如果x的类型为const int,则y的类型为int。也就是说,auto 剥离顶级cv限定符。
  • 如果x的类型为int[100],则y的类型为int*。也就是说,auto 执行数组到指针转换。 [1]
  • 如果x的类型为int f(int),则y的类型为int (*)(int)。也就是说,auto 执行函数指针转换功能。 [2]
  • 最后,如果x的类型为int&int&&,则y的类型为int。也就是说,auto 会删除引用

[1]你不能在这里使用decltype,因为你无法复制初始化数组。

[2]你不能在这里使用decltype,因为你无法初始化一个函数。

[3] auto剥离引用的原因是C ++没有引用类型的表达式!初始化后,引用的“引用”将变为不可见。

请注意,当decltype的参数不是id-expression时,{{1}}也会做一些完全不同的事情,我不会在这里讨论。

答案 4 :(得分:7)

每当您的变量类型与正在评估的表达式无关时。

E.g:

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

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

答案 5 :(得分:6)

decltype明显更加通用auto,并且可以随时用它代替它。因此,我认为decltype仅应用于完全必要的情况是非常安全的,因此如果auto产生错误的结果,则应使用decltype。此外,您还不能在返回类型和参数中使用auto,因此您也可以在其中使用decltype。 C ++ 14将显着增加auto的潜在用途,我猜想c ++ 17会更进一步。因此,只有当您需要更改decltype

的结果类型时,才会使用expr的情况

另一件需要考虑的事情是,除非你正在编写库代码,否则decltype并不是必需的,如果你想让你的代码更简洁,那么auto对于日常编程很有用,它可以用来讨论尽可能多auto是好的,但在使用像lambdas这样的不可言说的类型时,这几乎是必要的。