【问题标题】:Clang skips processing of an initializer list constructionClang 跳过初始化列表构造的处理
【发布时间】:2016-12-20 11:43:33
【问题描述】:

如果你看下面的代码,我认为main() 中的两行都应该为InitSomething 调用initializer_list 构造函数。 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'; }
    operator int() { return 1; }
};

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

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

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

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

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.

【问题讨论】:

  • 最近语言发生了一些变化,如果有其他构造函数直接采用some_value,则不支持每组{some_value}的initializer_list。
  • @BoPersson 你指的是 C++17 对吗?
  • 我不确定它是什么时候出现的。寻找参考...
  • 好的,我认为这与Core Defect Report #1467 - List-initialization of aggregate from same-type object 有关。这具有复杂性,如果它是 C++14 中的缺陷,则可能会追溯应用更改(作为对编译器的错误修复)。
  • @BoPersson InitSomething 不是聚合。

标签: c++ gcc clang c++14 language-lawyer


【解决方案1】:

DR1467 的标题涉及聚合,但 the wording it added to [dcl.init.list]/3 作为第一个项目符号并不限于聚合:

如果T 是一个类类型并且初始化列表只有一个元素 类型为cv U,其中U 是T 或派生自T 的类,则 对象从该元素初始化(通过复制初始化 复制列表初始化,或直接初始化 直接列表初始化)。

但是,DR2137 放弃了这种措辞(将“类类型”替换为“聚合类”),因此 this bullet 不再适用于像 InitSomething 这样的非聚合。

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

否则,如果 T 是类类型,则考虑构造函数。 列举了适用的构造函数和最好的一个 通过重载决议([over.match], [over.match.list])。

并且[over.match.list] 明确表示,如果可行的话,初始化列表构造函数是首选的:

当非聚合类类型T的对象被列表初始化时 [dcl.init.list] 指定执行重载决议 根据本节的规则,重载决议选择 构造函数分两个阶段:

  • 最初,候选函数是类 T 的初始化列表构造函数 ([dcl.init.list]) 和参数列表 由作为单个参数的初始化列表组成。
  • 如果没有找到可行的初始化列表构造函数,则再次执行重载决议,其中候选函数都是 T 类的构造函数和参数列表包括 初始化列表的元素。

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

Clang 正在执行 DR1467 之后和 DR2137 之前的措辞。

【讨论】:

  • 这种事情让我严重质疑initializer_list这个概念。
猜你喜欢
  • 2010-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-03
  • 1970-01-01
  • 2016-07-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多