Clang跳过初始化程序列表结构的处理 [英] Clang skips processing of an initializer list construction

查看:172
本文介绍了Clang跳过初始化程序列表结构的处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果你看下面的代码,我认为 main()中的两行应该调用 initializer_list InitSomething 的构造函数。 gcc输出 22 如我所料,但是clang只输出一个 2 。铛是错的?



我正在编译 -std = c ++ 14

  #include< iostream> 

struct InitSomething {
explicit InitSomething(int){std :: cout<< 1’ ; }
InitSomething(std :: initializer_list< int>){std :: cout<< 2’ ; }
操作符int(){return 1; }
};

int main(){
InitSomething init_something {1};
InitSomething init_something_else {init_something};






输出 clang ++ --version (我在Mac上)是

  Apple LLVM版本7.3.0(clang-703.0.31)
目标:x86_64-apple-darwin15.5.0
线程模型:posix
InstalledDir:/Applications/Xcode.app/Contents/Developer/Toolchains/ XcodeDefault.xctoolchain / usr / bin

g ++ --version的输出在我提到的另一个平台上是

  g ++(GCC)4.8.5 20150623(Red Hat 4.8 .5-4)
Copyright(C)2015 Free Software Foundation,Inc.
这是免费软件;请参阅复制条件的来源。没有任何b $ b保修;甚至不适用于适销性或针对特定用途的适用性。


解决方案

DR1467的标题涉及聚合,但它添加到[dcl.init.list] / 3 的措辞为如果 T 是一个类的类型,并且第一个项目符号不限于聚合:


初始化器列表中有一个单元素
,类型为 cv U ,其中 U T 或从 T 派生的类,
对象将从该元素初始化(通过
的复制初始化拷贝列表初始化,或者直接初始化
直接列表初始化)。

然而, DR2137 从这句话中走了回来(用聚合类替换类类型),所以这个项目符号不再适用于像 InitSomething 这样的非聚合项。



相反,应用[dcl.init.list] /3.6,就像它在DR1467之前一样:


否则,如果T是一个类类型,考虑构造函数。
枚举适用的构造函数,并通过重载解析([over.match],
[over.match.list])选择最好的


[over.match .list] 清楚地表明,如果可行的话,initializer-list构造函数是首选的: b
$ b


当非聚合类根据本节中的规则,类型 T 被列表初始化为
,[dcl.init.list]指定重载解析执行
,重载解析在两个阶段中选择
的构造函数:
$ b


  • 最初,候选函数是初始化列表构造函数([dcl。 T 和参数列表
    包含初始化列表作为单个参数。

  • 如果没有找到可行的初始化列表构造函数,重载决议是p再次执行,候选函数全部是
    T 的构造函数,参数列表包含
    初始化程序列表的元素。 / li>

所有关于排名隐式转换序列的讨论都是无关紧要的,因为非初始化列表构造函数甚至不是候选人



Clang在DR1467之后和DR2137之前实施措辞。


If you look at the following code, I think that both the lines in main() should call the initializer_list constructor for InitSomething. gcc outputs 22 as I expected, but clang just outputs a single 2. Is clang wrong?

I am compiling with -std=c++14.

#include <iostream>

struct InitSomething {
    explicit InitSomething(int) { std::cout << '1'; }
    InitSomething(std::initializer_list<int> ) { std::cout << '2'; }
    operator int() { return 1; }
};

int main() {
    InitSomething init_something{1};
    InitSomething init_something_else{init_something};
}


The output of clang++ --version (I am on a mac) is

Apple LLVM version 7.3.0 (clang-703.0.31)
Target: x86_64-apple-darwin15.5.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

and the output of g++ --version on the other platform I mentioned is

g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-4)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

解决方案

DR1467's title concerns aggregates, but the wording it added to [dcl.init.list]/3 as the first bullet is not limited to aggregates:

If T is a class type and the initializer list has a single element of type cv U, where U is T or a class derived from T, the object is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization).

However, DR2137 walked back from this wording (replacing "a class type" with "an aggregate class"), and so this bullet no longer applies to non-aggregates like InitSomething.

Instead, [dcl.init.list]/3.6 applies, like it did pre-DR1467:

Otherwise, if T is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen through overload resolution ([over.match], [over.match.list]).

And [over.match.list] makes clear that initializer-list constructors are preferred if at all viable:

When objects of non-aggregate class type T are list-initialized such that [dcl.init.list] specifies that overload resolution is performed according to the rules in this section, overload resolution selects the constructor in two phases:

  • Initially, the candidate functions are the initializer-list constructors ([dcl.init.list]) of the class T and the argument list consists of the initializer list as a single argument.
  • If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all the constructors of the class T and the argument list consists of the elements of the initializer list.

All this talk about ranking implicit conversion sequences is irrelevant because the non-initializer-list constructors are not even candidates.

Clang is implementing the wording after DR1467 and before DR2137.

这篇关于Clang跳过初始化程序列表结构的处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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