【问题标题】:How does auto decide the type of variable?auto 如何决定变量的类型?
【发布时间】:2020-12-18 01:42:03
【问题描述】:
#include <iostream>
int main() 
{
    auto n {42};
    cout << "The n has value of " << n <<
    " and a size of " << sizeof(n) << endl; // Works as expected
}
#include <iostream>
int main() 
{
    auto n = {42};
    cout << "The n has value of " << n <<
    " and a size of " << sizeof(n) << endl; // Does not work!
}

这是为什么呢? 在“A Tour of C++”中明确表示:

1.4.2 初始化 在一个对象可以被使用之前,它必须被赋予一个值。 C++ 提供了多种表示法 表示初始化,例如上面使用的 =,以及基于花括号分隔的初始化列表的通用形式:

    double d1 = 2.3; // initialize d1 to 2.3  
    double d2 {2.3}; // initialize d2 to 2.3  
    double d3 = {2.3}; // initialize d3 to 2.3 (the = is optional with { ... })
    complex<double> z2 {d1,d2};   
    complex<double> z3 = {d1,d2}; // the = is optional with { ... }  

= 是可选的 {}
那么,为什么会这样呢?

【问题讨论】:

  • 它工作得很好,但{42} 本身是std::initializer_list&lt;int&gt;,而不是int。创建一个由于其他原因而无法获得的变量的万无一失的方法是auto name = type{ args }; — 实际上,如果类型不可移动构造,即使在 c++11 中也会遇到问题(这在 c 中已修复++17).
  • Fwiw,this answer 展示了初始化列表、initializer_lists 和大括号初始化列表的微妙之处。
  • “不起作用!”?请说明它是如何不起作用的。如果有错误,请完整引用(不要发布屏幕截图)。

标签: c++ c++11


【解决方案1】:

这受[dcl.type.auto.deduct] 的规则约束,尤其是[dcl.type.auto.deduct]/1[dcl.type.auto.deduct]/4 [强调 我的]:

[dcl.type.auto.deduct]/1

占位符类型推导是一个类型包含一个 占位符类型替换为推导类型

[dcl.type.auto.deduct]/4

如果占位符是auto 类型说明符,则推导类型T' 替换T使用模板参数的规则确定的 扣除。从T 获取P 通过替换出现的 auto 使用新发明的类型模板参数 U ,或者,如果 初始化是复制列表初始化,其中 std​::​initializer_­list&lt;U&gt;。使用 从函数调用中推导模板参数的规则,其中P 是函数模板参数类型和对应的实参 是e。如果扣除失败,则声明格式错误。 否则,将推导出的U代入P,得到T'。 [ 示例:

auto x1 = { 1, 2 };    // decltype(x1) is std​::​initializer_­list<int>
auto x2 = { 1, 2.0 };  // error: cannot deduce element type
auto x3{ 1, 2 };       // error: not a single element
auto x4 = { 3 };       // decltype(x4) is std​::​initializer_­list<int>
auto x5{ 3 };          // decltype(x5) is int

 — 结束示例 ]

您的第二个示例是使用复制列表初始化,这意味着auto 被替换为,使用模板参数推导规则,std::initializer_list&lt;U&gt;,其中U 进一步推导出为int

auto n {42};    // deduced type is 'int'
auto m = {42};  // deduced type is 'std::initializer_list<int>'

这些规则特别适用于占位符类型扣除,因此不适用于非占位符类型的情况; op的后一个例子已经指定了类型,非类型推导适用。

// no placeholder type: type is 'double', and 'd1'
// through 'd3' simply uses different ways to initialize
// an object of (non-class fundamental) type 'double'.
double d1 = 2.3;   // copy initialization
double d2 {2.3};   // direct-list initialization; no narrowing allowed
double d3 = {2.3}; // copy-list-initialization (from C++11); no narrowing allowed

【讨论】:

    【解决方案2】:

    这两种初始化有细微的差别:

    auto n {42};  // n is of type int
    
    auto m = {42};  // m is of type initializer_list
    

    What Is a Curly-Brace Enclosed List If Not an intializer_list?

    typeid 可用于查找变量的确切类型,例如通过typeid(x).name()

    【讨论】:

      【解决方案3】:

      对于double d1 = {2.3};auto d2 = {2.3}; 这两种情况,{2.3} 是一个初始化列表。

      对于double d3{2.3};auto d4{2.3};{2.3} 不是初始化列表。

      但是对于第一种情况,你为d1指定它有什么类型,所以初始化器列表用于设置d1的值。但是对于d2,你告诉编译器选择类型,所以它将是初始化列表。

      所以= 不是可选的,如果您为d1 定义类型,则无法直接观察到差异。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-28
        • 1970-01-01
        • 2016-08-06
        • 2012-04-07
        相关资源
        最近更新 更多