为什么我不能使用大括号auto自动初始化值,并将其传递到此函数 [英] Why can't I initalize a value using braces with auto and pass it into this function

查看:142
本文介绍了为什么我不能使用大括号auto自动初始化值,并将其传递到此函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么我不能用auto初始化一个值,并将它传递给一个函数,期望一个decltype作为参数?

我设置场景,并显示一个小程序。

Let me set the scene, and show you a tiny program.

这是一个返回值的函数。

Here is a function that returns a value.

int Function(void);

在这种情况下,它恰好是一个整数,但返回类型可能会更改。 br>
这就是为什么这个下一个函数写成如下:

In this case, it happens to be an integer, but the return type is subject to change.
That is why this next function, is written as followed:

void What_I_Take_Depends_On_Function(decltype(Function()) x);

如果有人决定更改函数的返回类型, em>功能不需要改变。是的,函数的定义可能无法正确处理新类型,或者如果函数的返回类型更改为void,则会出现问题,但这与我的问题无关。

If someone decides to change the return type of Function, then the deceleration of this function will not need to be changed. Yes, the definition of the function may not handle the new type correctly, or if Function's return type is changed to void there will be an issue, but that is irrelevant to my problem.

#include <iostream>
#include <cstdlib>

int Function(void){return 5;}

void What_I_Take_Depends_On_Function(decltype(Function()) x){return;}

int main(){

    //assignments(Edit: these are initializations)
    int  var1 = Function();
    auto var2 = Function();

    //initializations
    int  var3 {Function()};
    auto var4 {Function()};

    What_I_Take_Depends_On_Function(var1); //works
    What_I_Take_Depends_On_Function(var2); //works
    What_I_Take_Depends_On_Function(var3); //works
    What_I_Take_Depends_On_Function(var4); //COMPILER ERROR

    //cannot convert ‘std::initializer_list<int>’ to ‘int’ for argument ‘1’ to ‘void What_I_Take_Depends_On_Function(int)’

    return EXIT_SUCCESS;
}

那么为什么var4是一个initializer_list而不是一个int?

无法自动只是推断函数要返回一个int,

,然后将减速度改为类似于var3?

So why is var4 an initializer_list and not an int?
Can't auto just deduce that Function is going to return an int,
and then change the deceleration to that similar of var3?

推荐答案

括号初始化列表 {...} 是C ++ 11的新的统一初始化语法,它可以用于初始化任何自动,静态或成员变量(如果该变量的类型已知)。这些是有效的C ++ 11初始化的几个例子:

The brace-init-list {...} is the new uniform initialization syntax for C++11, and it can be used to initialise any automatic, static or member variable if the type of that variable is known. These are a few examples of valid C++11 initialization:

class S
{
private:
  int _m;
public:
  S(int m) : _m { m }  // <== initialization of a member
  {}
};


int main() {

  constexpr unsigned i { 10 }; // <== initialization of a constexpr

  S s { i };  // <== initialization by calling constructor

  /* ... */
}

上述任何一种情况下都会生成 std :: initializer_list 。括号初始化列表 {...} 仅仅意味着编译器将尝试为给定数据类型标识合适的构造函数,其参数

In none of the above cases will a std::initializer_list be generated. The brace-init-list {...} simply means the compiler will try to identify a suitable constructor for the given data type, whose argument list matches the contents of the brace-init-list (§8.5.4).

两种特殊情况:


  1. 如果为给定数据类型定义的构造函数中包含 std :: initializer_list< T> 作为参数,并且括号初始列表的内容都可隐式转换为 T 。当您使用其中一种内置容器类型时,就是这种情况,例如

  1. If one of the constructors defined for the given data type takes a std::initializer_list<T> as argument, and the contents of the brace-init-list are all implicitly convertible to T. This is the case when you use one of the built-in container types, e.g.

std::vector<int> vec { 1, 2, 3 };

std :: vector< T> 构造函数 std :: vector< T>(const std :: initializer_list< T>),所以括号初始化列表将转换为 std :: initializer_list< int> ,并复制到向量构造函数中。构造函数将遍历列表并逐个追加元素。

std::vector<T> has a constructor std::vector<T>(const std::initializer_list<T>), so the brace-init-list will be converted to a std::initializer_list<int> and as such copied into the vector constructor. The constructor will iterate through the list and append the elements one by one.

当列表只包含一个参数时,这是一个陷阱:

This is a bit of a trap when the list contains only one argument:

std::vector<int> vec { 10 };

在这里,同样的情况,所以你会得到一个包含一个元素的向量 10 。这与使用旧样式语法不同:

Here, the same happens, so you will get a vector that contains the one element 10. This is different from using old-style syntax:

std::vector<int> vec(10);

这会调用 std :: vector< int>(const size_t) / code>构造函数,即它创建一个包含10个默认初始化元素的向量。

This calls the std::vector<int>(const size_t) constructor, i.e. it creates a vector of 10 default-initialised elements.

如果要初始化的变量的类型不是pre -

If the type of the variable to be initialised is not pre-determined, i.e. when auto is used in the declaration:

auto v { 1, 2, 3 };

在这种情况下(§7.1.6.4/ 6),编译器不能识别合适的构造函数,因为任何具有三个整数(或可转换为整数)参数的数据类型是可能的候选。这里的规则是编译器假设 v 的数据类型为 std :: initializer_list< int>

In this case (§7.1.6.4/6) the compiler cannot identify a suitable constructor, because any data type that takes three integer (or convertible-to-integer) arguments is a possible candidate. The rule here is that the compiler assumes std::initializer_list<int> as the data type for v. That is what happens in your case as well.

换句话说,使用括号初始化列表是很好的甚至鼓励)初始化,但你不能轻易地与 auto 组合。要解决你的问题,需要明确声明数据类型

In other words, using brace-init-lists is fine (and even encouraged) for initialization, but you can't readily combine it with auto. To solve you problem, you need to either declare the data type explicitly

int var4 { Function() };

或者,为了保持灵活性,请使用 decltype here too:

or, to keep things flexible, use decltype here too:

decltype(Function()) var4 { Function() };

或者,您可以使用旧式语法:

Alternatively, you can use old-style syntax:

auto v (Function());

这篇关于为什么我不能使用大括号auto自动初始化值,并将其传递到此函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆