std :: initializer_list作为函数参数 [英] std::initializer_list as function argument

查看:105
本文介绍了std :: initializer_list作为函数参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于某种原因,我认为C ++ 0x允许 std :: initializer_list 作为函数的函数参数,期望可以从这种类型构造的类型,例如 std :: vector 。但显然,它不工作。这只是我的编译器,或者这将不会工作?是因为潜在的重载解决问题吗?

For some reason I thought C++0x allowed std::initializer_list as function argument for functions that expect types that can be constructed from such, for example std::vector. But apparently, it does not work. Is this just my compiler, or will this never work? Is it because of potential overload resolution problems?

#include <string>
#include <vector>

void function(std::vector<std::string> vec)
{
}

int main()
{
    // ok
    std::vector<std::string> vec {"hello", "world", "test"};

    // error: could not convert '{"hello", "world", "test"}' to 'std::vector...'
    function( {"hello", "world", "test"} );
}


推荐答案

GCC有一个错误。标准使此有效。请参阅:

GCC has a bug. The Standard makes this valid. See:

请注意此



第一个问题在 8.5 部分中回答。第二个问题在 13.3 部分中回答。例如,引用绑定在 8.5.3 13.3.3.1.4 处理,而列表初始化在 8.5.4 13.3.3.1.5

The first question is answered in section 8.5. The second question is answered in section 13.3. For example, reference binding is handled at 8.5.3 and 13.3.3.1.4, while list initialization is handled in 8.5.4 and 13.3.3.1.5.

8.5 / 14,16


The initialization that occurs in the form

T x = a;

以及参数传递,函数返回,抛出异常15.1),处理异常(15.3)和聚合成员初始化(8.5.1)称为复制初始化。





语义[...]如果初始化器是一个支撑初始化列表,对象被列表初始化(8.5.4)。

as well as in argument passing, function return, throwing an exception (15.1), handling an exception (15.3), and aggregate member initialization (8.5.1) is called copy-initialization.
.
.
The semantics of initializers are as follows[...]: If the initializer is a braced-init-list, the object is list-initialized (8.5.4).

当考虑候选 function 时,编译器将看到一个初始化列表(它没有类型 - 它只是一个语法结构!)作为参数和 std :: vector< std :: string> 作为 function 的参数。要确定转化费用是否是我们是否可以在重载上下文中进行转换, 13.3.3.1/5 表示

When considering the candidate function, the compiler will see an initializer list (which has no type yet - it's just a grammatical construct!) as the argument, and a std::vector<std::string> as the parameter of function. To figure out what the cost of conversion is and whether we can convert these in context of overloading, 13.3.3.1/5 says

13.3.3.1.5 / 1


当参数是初始化器列表(8.5.4)时,它不是一个表达式,并且特殊规则适用于将其转换为参数类型。

When an argument is an initializer list (8.5.4), it is not an expression and special rules apply for converting it to a parameter type.

13.3.3.1.5 / 3


否则,如果参数是非聚合类X,并且重载分辨率根据13.3.1.7选择X的单个最佳构造函数以从参数初始化器列表执行类型X的对象的初始化,则隐式转换序列是用户定义的,定义的转换序列。允许用户定义的转换将初始化列表元素转换为构造函数参数类型,除非13.3.3.1中所述。

Otherwise, if the parameter is a non-aggregate class X and overload resolution per 13.3.1.7 chooses a single best constructor of X to perform the initialization of an object of type X from the argument initializer list, the implicit conversion sequence is a user-defined conversion sequence. User-defined conversions are allowed for conversion of the initializer list elements to the constructor parameter types except as noted in 13.3.3.1.

非聚合类 X std :: vector< std :: string> ,我会找出单最好的构造函数。最后一个规则允许我们在下列情况下使用用户定义的转换:

The non-aggregate class X is std::vector<std::string>, and i will figure out the single best constructor below. The last rule grants us to use user defined conversions in cases like the following:

struct A { A(std::string); A(A const&); };
void f(A);
int main() { f({"hello"}); }

我们允许将字符串文字转换为 std :: string ,即使这需要用户定义的转换。但是,它指出了另一段的限制。 13.3.3.1 说什么?

We are allowed to convert the string literal to std::string, even if this needs a user defined conversion. However, it points to restrictions of another paragraph. What does 13.3.3.1 say?

13.3.3.1/4 ,这是负责禁止多个用户定义的转化的段落。我们只看一下列表初始化:

13.3.3.1/4, which is the paragraph responsible for forbidding multiple user defined conversions. We will only look at list initializations:


然而,当考虑用户定义的转换函数[是一个候选者[...] 13.3.1.7当初始化器列表作为单个参数传递时,或者当初始化器列表有一个元素,并转换为某个类X或引用(可能是cv-qualifer)X被认为是X的构造函数的第一个参数或[...],只允许标准转换序列和省略号转换序列。

However, when considering the argument of a user-defined conversion function [(or constructor)] that is a candidate by [...] 13.3.1.7 when passing the initializer list as a single argument or when the initializer list has exactly one element and a conversion to some class X or reference to (possibly cv-qualified) X is considered for the first parameter of a constructor of X, or [...], only standard conversion sequences and ellipsis conversion sequences are allowed.

注意,这是一个重要的限制:如果不是这样,上面可以使用复制构造函数建立一个同样好的转换序列,并且初始化将是不明确的。 (注意在该规则中A或B和C的潜在混淆:这意味着(A或B)和C - 因此我们仅在 $

Notice that this is an important restriction: If it weren't for this, the above can use the copy-constructor to establish an equally well conversion sequence, and the initialization would be ambiguous. (notice the potential confusion of "A or B and C" in that rule: It is meant to say "(A or B) and C" - so we are restricted only when trying to convert by a constructor of X having a parameter of type X).

我们被委托给 13.3 .1.7 用于收集我们可以用来执行此转换的构造函数。让我们从 8.5 开始,将我们委托给 8.5.4

We are delegated to 13.3.1.7 for collecting the constructors we can use to do this conversion. Let's approach this paragraph from the general side starting from 8.5 which delegated us to 8.5.4:

8.5.4 / 1


列表初始化可以发生在直接初始化或复制初始化上下文中;在直接初始化上下文中的列表初始化被称为直接列表初始化,并且在复制初始化上下文中的列表初始化被称为复制列表初始化。

List-initialization can occur in direct-initialization or copy-initialization contexts; list-initialization in a direct-initialization context is called direct-list-initialization and list-initialization in a copy-initialization context is called copy-list-initialization.

8.5.4 / 2


如果构造函数的第一个参数的类型为 std :: initializer_list< E>,则构造函数是一个初始化函数列表构造函数 / code>或对某些类型E引用可能cv-qualal的 std :: initializer_list< E> ,并且没有其他参数或者所有其他参数有默认参数(8.3.6)。

A constructor is an initializer-list constructor if its first parameter is of type std::initializer_list<E> or reference to possibly cv-qualified std::initializer_list<E> for some type E, and either there are no other parameters or else all other parameters have default arguments (8.3.6).

8.5.4 / 3


类型T的对象或引用的列表初始化定义如下:[...]否则,如果T是类类型,则考虑构造函数。如果T有一个初始化器列表构造函数,参数列表由作为单个参数的初始化器列表组成;否则,参数列表由初始化程序列表的元素组成。适用的构造函数枚举(13.3.1.7),最好的构造函数通过重载解析(13.3)选择。

List-initialization of an object or reference of type T is defined as follows: [...] Otherwise, if T is a class type, constructors are considered. If T has an initializer-list constructor, the argument list consists of the initializer list as a single argument; otherwise, the argument list consists of the elements of the initializer list. The applicable constructors are enumerated (13.3.1.7) and the best one is chosen through overload resolution (13.3).

T 是类类型 std :: vector< std :: string> 。我们有一个参数(它没有类型!我们只是在语法初始化列表的上下文中)。构造函数枚举为 13.3.1.7

At this time, T is the class type std::vector<std::string>. We have one argument (which does not have a type yet! We are just in the context of having a grammatical initializer list). Constructors are enumerated as of 13.3.1.7:


[...] T具有初始化列表构造函数(8.5.4),参数列表由作为单个参数的初始化列表组成;否则,参数列表由初始化程序列表的元素组成。对于复制列表初始化,候选函数是T的所有构造函数。但是,如果选择显式构造函数,初始化是不成立的。

[...] If T has an initializer-list constructor (8.5.4), the argument list consists of the initializer list as a single argument; otherwise, the argument list consists of the elements of the initializer list. For copy-list-initialization, the candidate functions are all the constructors of T. However, if an explicit constructor is chosen, the initialization is ill-formed.

我们将只考虑 std :: vector 的初始化器列表只有候选人,因为我们已经知道,其他人不会赢得反对或不适合的论点。它具有以下签名:

We will only consider the initializer list of std::vector as the only candidate, since we already know the others won't win against it or won't fit the argument. It has the following signature:

vector(initializer_list<std::string>, const Allocator& = Allocator());

现在,将初始化器列表转换为 std :: initializer_list< ; 13.3.3.1.5

Now, the rules of converting an initializer list to an std::initializer_list<T> (to categorize the cost of the argument/parameter conversion) are enumerated in 13.3.3.1.5:


当参数是初始化器列表(8.5.4)时,它不是一个表达式,特殊规则适用于将其转换为参数类型。 [...]如果参数类型是 std :: initializer_list< X> ,并且初始化器列表的所有元素可以隐式地转换为X,隐式转换序列将列表元素转换为X所需的最差转换。即使在调用初始化列表构造函数的上下文中,此转换也可以是用户定义的转换

When an argument is an initializer list (8.5.4), it is not an expression and special rules apply for converting it to a parameter type. [...] If the parameter type is std::initializer_list<X> and all the elements of the initializer list can be implicitly converted to X, the implicit conversion sequence is the worst conversion necessary to convert an element of the list to X. This conversion can be a user-defined conversion even in the context of a call to an initializer-list constructor.

现在,初始化器列表将被成功转换,转换序列是一个用户定义的转换(从 char const [N] / code>到 std :: string )。如何进行此操作将在 8.5.4 中详细说明:

Now, the initializer list will be successfully converted, and the conversion sequence is a user defined conversion (from char const[N] to std::string). How this is made is detailed at 8.5.4 again:


T是 std :: initializer_list< E> 的特殊化,initializer_list对象如下所述被构造并且用于根据用于对象的初始化的规则来初始化对象相同类型的类(8.5)。 (...)

Otherwise, if T is a specialization of std::initializer_list<E>, an initializer_list object is constructed as described below and used to initialize the object according to the rules for initialization of an object from a class of the same type (8.5). (...)

请参阅 8.5.4 / 4 步骤为:)

这篇关于std :: initializer_list作为函数参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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