std::initializer_list 作为函数参数
出于某种原因,我认为 C++0x 允许 std::initializer_list
作为期望可以从中构造类型的函数的函数参数,例如 std::vector
。但显然,它不起作用。这只是我的编译器,还是永远不会工作?是因为潜在的重载解决问题吗?
#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"} );
}
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"} );
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
海湾合作委员会有一个错误。该标准使这一点有效。请参阅:
请注意,此问题有两个方面:
第一个问题在
8.5
部分得到了解答。第二个问题在13.3
部分得到解答。例如,引用绑定在8.5.3
和13.3.3.1.4
中处理,而列表初始化在8.5.4
和 <代码>13.3.3.1.5。8.5/14,16
:当考虑候选函数时,编译器将看到一个初始化列表(它还没有类型 - 它只是一个语法构造!)作为参数,以及一个 std::vector作为
function
的参数。为了弄清楚转换成本是多少以及我们是否可以在重载的情况下转换这些成本,13.3.3.1/5
表示13.3.3.1.5/1 :
13.3.3.1.5/3:
非聚合类
X
是std::vector
,我将在下面找出最好的构造函数。最后一条规则允许我们在以下情况下使用用户定义的转换:我们可以将字符串文字转换为
std::string
,即使这需要用户定义的转换。然而,它指出了另一段的限制。13.3.3.1
说什么?13.3.3.1/4
,这是负责禁止多个用户定义转换的段落。我们只看列表初始化:请注意,这是一个重要的限制:如果不是这样,上面的代码可以使用复制构造函数来建立同样良好的转换序列,并且初始化将是不明确的。 (请注意该规则中“A 或 B 和 C”的潜在混淆:它的意思是“(A 或 B)和 C” - 所以我们仅在尝试通过 a 进行转换时受到限制X 的构造函数具有
X
类型的参数)。我们被委托给
13.3.1.7
来收集可用于执行此转换的构造函数。让我们从一般的角度来看待这一段,从8.5
开始,它委托我们到8.5.4
:8.5.4/1
:8.5.4/2:
8.5.4/3:
此时,
T
就是类类型std::vector
。我们有一个参数(它还没有类型!我们只是在一个语法初始化列表的上下文中)。从13.3.1.7
开始枚举构造函数:我们只会将
std::vector
的初始值设定项列表视为唯一候选者,因为我们已经知道其他列表不会赢得它或不适合该参数。它具有以下签名:现在,将初始值设定项列表转换为
std::initializer_list
的规则(对参数/参数转换的成本进行分类)在13.3 中枚举.3.1.5
:现在,初始化列表将被成功转换,并且转换序列是用户定义的转换(从 char const[N] 到 std::string )。这是如何实现的,在
8.5.4
中再次详细说明:请参阅
8.5.4/4
最后一步是如何完成的:)GCC has a bug. The Standard makes this valid. See:
Notice that there are two sides of this
The first question is answered in section
8.5
. The second question is answered in section13.3
. For example, reference binding is handled at8.5.3
and13.3.3.1.4
, while list initialization is handled in8.5.4
and13.3.3.1.5
.8.5/14,16
: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 astd::vector<std::string>
as the parameter offunction
. To figure out what the cost of conversion is and whether we can convert these in context of overloading,13.3.3.1/5
says13.3.3.1.5/1
:13.3.3.1.5/3
:The non-aggregate class
X
isstd::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: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 does13.3.3.1
say?13.3.3.1/4
, which is the paragraph responsible for forbidding multiple user defined conversions. We will only look at list initializations: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
).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 from8.5
which delegated us to8.5.4
:8.5.4/1
:8.5.4/2
:8.5.4/3
:At this time,
T
is the class typestd::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 of13.3.1.7
: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: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 in13.3.3.1.5
:Now, the initializer list will be successfully converted, and the conversion sequence is a user defined conversion (from
char const[N]
tostd::string
). How this is made is detailed at8.5.4
again:See
8.5.4/4
how this final step is made :)它似乎是这样工作的:
也许这是一个编译器错误,但也许您要求太多隐式转换。
It seems to work this way:
Perhaps it is a compiler bug, but perhaps you are asking for too many implicit conversions.
顺便说一句,我不确定,但我怀疑这里发生的事情是转换为initializer_list是一种转换,而将其转换为向量是另一种转换。如果是这种情况,那么您就超出了仅一次隐式转换的限制......
Offhand, I'm not sure, but I suspect what's going on here is that converting to an initializer_list is one conversion, and converting that to vector is another conversion. If that's the case, you're exceeding the limit of only one implicit conversion...
这要么是编译器错误,要么是您的编译器不支持 std::initializer_list。在 GCC 4.5.1 上测试,编译良好。
This is either a compiler bug or your compiler doesn't support std::initializer_list. Tested on GCC 4.5.1 and it compiles fine.