rejecting/accepting 这个 CTAD 代码中的 Clang 或 GCC 是否正确?
Is Clang or GCC correct in rejecting/accepting this CTAD code?
Clang 和 GCC disagree 接受此代码。
标准要求的行为是什么?
#include <utility>
#include <iostream>
#include <vector>
int main()
{
std::vector pairs = {std::pair{1,11},{2,22}, {3,33}};
for (const auto& p: pairs) {
std::cout << p.second << std::endl;
}
}
注意:我知道这是 C++,所以标准可能是模糊的,但我认为一种行为是正确的。
CTAD 的进程主要由 [over.match.class.deduct] 定义。从广义上讲,重载集是该类型的所有可访问构造函数,加上任何推导指南。并且根据此规则解决了重载集:
Initialization and overload resolution are performed as described in [dcl.init] and [over.match.ctor], [over.match.copy], or [over.match.list] (as appropriate for the type of initialization performed)
由于“执行的初始化类型”肯定是列表初始化,我们继续 [over.match.list]。我们从哪里得到这个臭名昭著的项目符号列表:
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.
这告诉我们 initializer-list constructors
是优先的;他们首先以一种非常具体的方式解决了重载问题(即构建 std::initializer_list
并将其作为参数传递)。但是,Clang 给出了一个明显的错误:
note: candidate function template not viable: requires at most 2 arguments, but 3 were provided
vector(initializer_list<value_type> __l,
也就是说,它试图调用该构造函数,就像“参数列表由初始化列表的元素组成”一样。这表明 Clang 跳过了 通过 CTAD 进行列表初始化时的第一个要点。在 braced-init-list 周围添加括号“修复”了这个问题的事实也表明这就是正在发生的事情。
奇怪的是,它适用于简单类型,例如整数的初始化列表。如果您将每个成员明确命名为 pair
,它就会起作用。并且 Clang 可以 auto
推断出 {std::pair{1,11}, {2,22}, {3,33}}
生成的 initializer_list
的类型就好了。所以这个错误似乎 确实 具体。
Clang 和 GCC disagree 接受此代码。
标准要求的行为是什么?
#include <utility>
#include <iostream>
#include <vector>
int main()
{
std::vector pairs = {std::pair{1,11},{2,22}, {3,33}};
for (const auto& p: pairs) {
std::cout << p.second << std::endl;
}
}
注意:我知道这是 C++,所以标准可能是模糊的,但我认为一种行为是正确的。
CTAD 的进程主要由 [over.match.class.deduct] 定义。从广义上讲,重载集是该类型的所有可访问构造函数,加上任何推导指南。并且根据此规则解决了重载集:
Initialization and overload resolution are performed as described in [dcl.init] and [over.match.ctor], [over.match.copy], or [over.match.list] (as appropriate for the type of initialization performed)
由于“执行的初始化类型”肯定是列表初始化,我们继续 [over.match.list]。我们从哪里得到这个臭名昭著的项目符号列表:
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.
这告诉我们 initializer-list constructors
是优先的;他们首先以一种非常具体的方式解决了重载问题(即构建 std::initializer_list
并将其作为参数传递)。但是,Clang 给出了一个明显的错误:
note: candidate function template not viable: requires at most 2 arguments, but 3 were provided vector(initializer_list<value_type> __l,
也就是说,它试图调用该构造函数,就像“参数列表由初始化列表的元素组成”一样。这表明 Clang 跳过了 通过 CTAD 进行列表初始化时的第一个要点。在 braced-init-list 周围添加括号“修复”了这个问题的事实也表明这就是正在发生的事情。
奇怪的是,它适用于简单类型,例如整数的初始化列表。如果您将每个成员明确命名为 pair
,它就会起作用。并且 Clang 可以 auto
推断出 {std::pair{1,11}, {2,22}, {3,33}}
生成的 initializer_list
的类型就好了。所以这个错误似乎 确实 具体。