为什么不能使用带有花括号的auto初始化值并将其传递给此函数 [英] Why can't I initialize a value using braces with auto and pass it into this function

查看:139
本文介绍了为什么不能使用带有花括号的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);

在这种情况下,它恰好是整数,但是返回类型可能会发生变化.
这就是为什么下一个函数编写如下:

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);

如果某人决定更改Function的返回类型,则无需更改 this 函数的减速度.是的,函数的定义可能无法正确处理新类型,或者如果将函数的返回类型更改为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?
无法自动推断出Function将要返回一个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?

推荐答案

brace-init-list {...}是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. brace-init-list {...}只是意味着编译器将尝试为给定的数据类型标识合适的构造函数,其参数列表与brace-init-list的内容匹配(第8.5节). 4).

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>作为参数,则brace-init-list的内容为全部隐式转换为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>),因此brace-init-list将转换为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)构造函数,即它会创建一个包含10个默认初始化元素的向量.

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

如果未预先确定要初始化的变量的类型,即在声明中使用auto时:

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.6.4节),编译器无法识别合适的构造函数,因为采用三个整数(或可转换为整数)参数的任何数据类型都是可能的候选对象.此处的规则是,编译器将std::initializer_list<int>假定为v的数据类型.您的情况也是如此.

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.

换句话说,使用brace-init-lists可以很好地进行初始化(甚至鼓励),但是您不能轻易将其与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:

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天全站免登陆