- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
考虑以下几点:
struct A {
A(int, int) { }
};
struct B {
B(A ) { } // (1)
explicit B(int, int ) { } // (2)
};
int main() {
B paren({1, 2}); // (3)
B brace{1, 2}; // (4)
}
(4)
中brace
的构造清楚明确地调用了(2)
。在 clang 上,(3)
中 paren
的构造明确调用了 (1)
,而在 gcc 5.2 上,它无法编译:
main.cpp: In function 'int main()':
main.cpp:11:19: error: call of overloaded 'B(<brace-enclosed initializer list>)' is ambiguous
B paren({1, 2});
^
main.cpp:6:5: note: candidate: B::B(A)
B(A ) { }
^
main.cpp:5:8: note: candidate: constexpr B::B(const B&)
struct B {
^
main.cpp:5:8: note: candidate: constexpr B::B(B&&)
哪个编译器是正确的?我怀疑 clang 在这里是正确的,因为 gcc 中的歧义只能通过涉及隐式构造 B{1,2}
并将其传递给复制/移动构造函数的路径出现 - 但该构造函数被标记显式
,因此不应允许这种隐式构造。
最佳答案
据我所知,这是一个 clang 错误。
Copy-list-initialization 有一个相当不直观的行为:它认为显式构造函数在重载决议完全完成之前是可行的,但如果选择了显式构造函数,则可以拒绝重载结果。 N4567 后草案中的措辞,[over.match.list]p1
In copy-list-initialization, if an
explicit
constructor is chosen, the initialization is ill-formed. [ Note: This differs from other situations (13.3.1.3, 13.3.1.4), where only converting constructors are considered for copy-initialization. This restriction only applies if this initialization is part of the final result of overload resolution. — end note ]
clang HEAD 接受以下程序:
#include <iostream>
using namespace std;
struct String1 {
explicit String1(const char*) { cout << "String1\n"; }
};
struct String2 {
String2(const char*) { cout << "String2\n"; }
};
void f1(String1) { cout << "f1(String1)\n"; }
void f2(String2) { cout << "f2(String2)\n"; }
void f(String1) { cout << "f(String1)\n"; }
void f(String2) { cout << "f(String2)\n"; }
int main()
{
//f1( {"asdf"} );
f2( {"asdf"} );
f( {"asdf"} );
}
也就是说,除了注释掉对 f1
的调用外,直接来自 Bjarne Stroustrup 的 N2532 - Uniform initialization 第 4 章。感谢 Johannes Schaub 向我展示了这篇关于 std-discussion 的论文。
同一章节包含以下解释:
The real advantage of
explicit
is that it rendersf1("asdf")
an error. A problem is that overload resolution “prefers” non-explicit
constructors, so thatf("asdf")
callsf(String2)
. I consider the resolution off("asdf")
less than ideal because the writer ofString2
probably didn’t mean to resolve ambiguities in favor ofString2
(at least not in every case where explicit and non-explicit constructors occur like this) and the writer ofString1
certainly didn’t. The rule favors “sloppy programmers” who don’t useexplicit
.
据我所知,N2640 - Initializer Lists — Alternative Mechanism and Rationale 是最后一篇包含这种重载决议原理的论文;它的继任者 N2672 被选入 C++11 草案。
摘自“显式的含义”一章:
A first approach to make the example ill-formed is to require that all constructors (explicit and non-explicit) are considered for implicit conversions, but if an explicit constructor ends up being selected, that program is ill-formed. This rule may introduce its own surprises; for example:
struct Matrix {
explicit Matrix(int n, int n);
};
Matrix transpose(Matrix);
struct Pixel {
Pixel(int row, int col);
};
Pixel transpose(Pixel);
Pixel p = transpose({x, y}); // Error.A second approach is to ignore the explicit constructors when looking for the viability of an implicit conversion, but to include them when actually selecting the converting constructor: If an explicit constructor ends up being selected, the program is ill-formed. This alternative approach allows the last (Pixel-vs-Matrix) example to work as expected (
transpose(Pixel)
is selected), while making the original example ("X x4 = { 10 };
") ill-formed.
虽然这篇论文建议使用第二种方法,但它的措辞似乎有缺陷——在我对措辞的解释中,它不会产生论文的基本原理部分概述的行为。 N2672 中的措辞被修改为使用第一种方法,但我找不到任何关于为什么改变的讨论。
当然,在 OP 中初始化变量涉及的措辞略多,但考虑到 clang 和 gcc 之间的行为差异对于我的回答中的第一个示例程序是相同的,我认为这涵盖了要点。
关于c++ - 使用花括号初始化列表调用显式构造函数 : ambiguous or not?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49264846/
我是一名优秀的程序员,十分优秀!