gpt4 book ai didi

C++11 构造函数重载解析和初始化列表 : clang++ and g++ disagree

转载 作者:可可西里 更新时间:2023-11-01 17:56:11 26 4
gpt4 key购买 nike

我有一小段 C++11 代码,g++(4.7 或 4.8)拒绝编译,声称对 B2 b2a(x, {P(y)}) 的构造函数的调用不明确。 Clang++ 对这些代码很满意,但拒绝编译 B2 b2b(x, {{P(y)}}) 而 g++ 很乐意编译!

两个编译器都非常满意以 {...} 或 {{...}} 作为参数的 B1 构造函数。任何 C++ 语言律师都可以解释哪个编译器是正确的(如果有的话)以及发生了什么?代码如下:

#include <initializer_list>

using namespace std;

class Y {};
class X;

template<class T> class P {
public:
P(T);
};

template<class T> class A {
public:
A(initializer_list<T>);
};

class B1 {
public:
B1(const X&, const Y &);
B1(const X&, const A<Y> &);
};

class B2 {
public:
B2(const X &, const P<Y> &);
B2(const X &, const A<P<Y>> &);
};

int f(const X &x, const Y y) {
B1 b1a(x, {y});
B1 b1b(x, {{y}});
B2 b2a(x, {P<Y>(y)});
B2 b2b(x, {{P<Y>(y)}});
return 0;
}

和编译器错误,clang:
$ clang++ -stdlib=libc++ -std=c++11 test-initialiser-list-4.cc -o test.o -c 
test-initialiser-list-4.cc:32:6: error: call to constructor of 'B2' is ambiguous
B2 b2(x, {{P<Y>(y)}});
^ ~~~~~~~~~~~~~~
test-initialiser-list-4.cc:26:5: note: candidate constructor
B2(const X &, const P<Y> &);
^
test-initialiser-list-4.cc:27:5: note: candidate constructor
B2(const X &, const A<P<Y>> &);
^

克++:
test-initialiser-list-4.cc: In function 'int f(const X&, Y)':
test-initialiser-list-4.cc:32:21: error: call of overloaded 'B2(const X&, <brace-enclosed initializer list>)' is ambiguous
B2 b2(x, {P<Y>(y)});
^
test-initialiser-list-4.cc:32:21: note: candidates are:
test-initialiser-list-4.cc:27:5: note: B2::B2(const X&, const A<P<Y> >&)
B2(const X &, const A<P<Y>> &);
^
test-initialiser-list-4.cc:26:5: note: B2::B2(const X&, const P<Y>&)
B2(const X &, const P<Y> &);
^

这闻起来像是统一初始化、初始化列表语法和带有模板化参数的函数重载之间的交互(我知道 g++ 对此相当严格),但我还不足以成为标准律师,无法解开什么应该是正确的行为这里!

最佳答案

首先是代码,然后是我认为应该发生的事情。 (在接下来的内容中,我将忽略第一个参数,因为我们只对第二个参数感兴趣。在您的示例中,第一个参数始终是完全匹配的)。请注意,规范中的规则目前在不断变化,所以我不会说一个或另一个编译器有错误。

B1 b1a(x, {y});

此代码无法调用 const Y& C++11 中的构造函数,因为 Y是一个聚合和 Y没有 Y 类型的数据成员(当然)或其他可由它初始化的东西(这是丑陋的东西,正在努力修复 - C++14 CD 还没有对此的措辞,所以我不确定最终的 C++14将包含此修复程序)。

带有 const A<Y>& 的构造函数可以调用参数 - {y}将作为 A<Y> 的构造函数的参数,并将初始化该构造函数的 std::initializer_list<Y> .

因此 - 第二个构造函数调用成功。
B1 b1b(x, {{y}});

在这里,基本相同的参数对具有 const Y& 的构造函数计数。范围。

对于参数类型为 const A<Y>& 的构造函数,有点复杂。计算初始化成本的重载决议中的转换成本规则 std::initializer_list<T>要求花括号列表的每个元素都可以转换为 T .然而我们之前说过 {y}无法转换为 Y (因为它是一个聚合)。现在重要的是要知道 std::initializer_list<T>是不是聚合。坦率地说,我不知道根据标准库条款是否必须将其视为聚合。

如果我们将其视为非聚合,那么我们将考虑 std::initializer_list<Y> 的复制构造函数。 ,然而这将再次触发完全相同的测试序列(导致重载决议检查中的“无限递归”)。由于这相当奇怪且无法实现,我认为任何实现都不会走这条路。

如果我们取 std::initializer_list作为一个聚合,我们会说“不,没有找到转换”(参见上面的聚合问题)。在这种情况下,由于我们不能将单个初始化列表作为一个整体调用初始化构造函数, {{y}}将被拆分为多个参数,以及 A<Y> 的构造函数将分别考虑其中的每一个。因此,在这种情况下,我们最终会得到 {y}初始化 std::initializer_list<Y>作为单个参数 - 这非常好并且像魅力一样工作。

所以假设 std::initializer_list<T>是一个聚合,这很好,成功调用第二个构造函数。

B2 b2a(x, {P<Y>(y)});


在这种情况下和下一种情况下,我们没有像上面 Y 那样的聚合问题。不再,因为 P<Y>有一个用户提供的构造函数。

对于 P<Y>参数构造函数,该参数将由 {P<Y> object} 初始化.如 P<Y>没有初始化列表,列表将被拆分为单独的参数并调用 P<Y> 的移动构造函数右值对象为 P<Y> .

对于 A<P<Y>>参数构造函数,与上面的情况相同,有 A<Y>{y} 初始化: 自 std::initializer_list<P<Y>>可以通过 {P<Y> object} 初始化,参数列表没有被拆分,因此大括号用于初始化构造函数的 S std::initializer_list<T> .

现在,两个构造函数都可以正常工作。它们在这里就像重载函数一样,并且在这两种情况下它们的第二个参数都需要用户定义的转换。只有在两种情况下都使用相同的转换函数或构造函数时,才能比较用户定义的转换序列——这里不是这种情况。因此,这在 C++11(和 C++14 CD)中是不明确的。

请注意,这里我们要探索一个微妙的点
struct X { operator int(); X(){/*nonaggregate*/} };

void f(X);
void f(int);

int main() {
X x;
f({x}); // ambiguity!
f(x); // OK, calls first f
}

这个反直觉的结果可能会在同一次运行中修复,同时修复上面提到的聚合初始化的怪异(两者都会调用第一个 f)。这是通过说 {x}->X 来实现的成为身份转换(如 X->x )。目前,它是一个用户定义的转换。

所以,这里有歧义。
B2 b2b(x, {{P<Y>(y)}});

对于带参数 const P<Y>& 的构造函数,我们再次拆分参数并得到 {P<Y> object}传递给 P<Y> 的构造函数的参数.请记住 P<Y>有一个复制构造函数。但这里的复杂之处在于我们不允许使用它(参见 13.3.3.1p4),因为它需要用户定义的转换。剩下的唯一构造函数是使用 Y 的构造函数。 ,但是一个 Y不能被 {P<Y> object} 初始化.

对于带参数 A<P<Y>> 的构造函数, {{P<Y> object}}可以初始化一个 std::initializer_list<P<Y>> , 因为 {P<Y> object}可转换为 P<Y> (除了上面的 Y - dang,聚合)。

因此,第二个构造函数调用成功。

所有 4 的总结
  • 第二个构造函数调用成功
  • 假设std::initializer_list<T>是一个聚合,这很好,成功调用第二个构造函数
  • 这里有歧义
  • 第二个构造函数调用成功
  • 关于C++11 构造函数重载解析和初始化列表 : clang++ and g++ disagree,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17704732/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com