以下代码在g ++ 4.9.2和clang ++ 3.7.0下表现不同。哪一个是正确的?标准中的哪一部分与此相关?感谢。
#include <iostream>
using namespace std;
struct Base {
Base() = default;
Base(const Base&) = default;
Base(Base&&) = delete;
};
struct Derived : Base {
};
int main() {
const Base& b = true ? Derived() : Base();
}
g ++接受它并且clang ++给出错误incompatible operand types ('Derived' and 'Base')
。有关详细信息,请参阅下文。
[hidden]$ g++ -v
Using built-in specs.
COLLECT_GCC=/usr/bin/g++
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.9.2/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.9.2-20150212/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.9.2-20150212/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
Thread model: posix
gcc version 4.9.2 20150212 (Red Hat 4.9.2-6) (GCC)
[hidden]$ g++ -std=c++11 b.cpp
[hidden]$ clang++ -v
clang version 3.7.0 (http://llvm.org/git/clang.git 6bbdbba8ec8a7730c68fee94363547dc2dc65b10)
Target: x86_64-unknown-linux-gnu
Thread model: posix
Found candidate GCC installation: /usr/lib/gcc/x86_64-redhat-linux/3.4.6
Found candidate GCC installation: /usr/lib/gcc/x86_64-redhat-linux/4.9.2
Selected GCC installation: /usr/lib/gcc/x86_64-redhat-linux/4.9.2
Candidate multilib: .;@m64
Candidate multilib: 32;@m32
Selected multilib: .;@m64
[hidden]$ clang++ -std=c++11 b.cpp
b.cpp:14:24: error: incompatible operand types ('Derived' and 'Base')
const Base& b = true ? Derived() : Base();
^ ~~~~~~~~~ ~~~~~~
1 error generated.
答案 0 :(得分:7)
我没有N3936方便,但N3797§5.12[expr.cond] / 3包含了这个(强调我的):
否则,如果第二个和第三个操作数具有不同的类型和 要么具有(可能是cv-qualified)类类型,要么两者都是glvalues 相同值类别和相同类型除外 cv-qualification,尝试转换每个操作数 到另一种的类型。确定是否的过程 可以转换类型T1的操作数表达式E1以匹配操作数 T2型表达式E2定义如下:
- 如果E2是左值:[已删除]
- 如果E2是xvalue:[已移除]
- 如果E2是prvalue或两者都没有转换 可以完成上面的操作并且至少有一个操作数(可能是 cv-qualified)类类型:
- 如果 E1和E2有类型,那么 底层类类型是相同的或一个是基类 其他强>:
如果T2的类相同,则E1可以被转换为匹配E2 键入as,或的基类,T1的类和cv-qualification T2的资格与cv资格相同,或更高的cv资格 比,T1的cv资格。如果应用转换,则E1为 通过复制初始化暂时更改为T2类型的prvalue 从E1键入T2并使用该临时值作为转换后的操作数。使用此过程,确定第二个操作数是否可以 转换为匹配第三个操作数,以及是否为第三个操作数 可以转换为匹配第二个操作数。如果两者都可以 转换,或者一个可以转换,但转换是模糊的, 该计划格式不正确。如果两者都不能转换,则操作数 保持不变,并如所述进行进一步检查 下面。 如果只能进行一次转换,则转换为 应用于所选操作数,并使用转换后的操作数 本节其余部分的原始操作数的位置。
现在从Base
复制初始化最终的Derived()
操作数,我们可以看一下§13.3.1.3[over.match.ctor]:
当类类型的对象被直接初始化(8.5)或者 从相同或派生类的表达式复制初始化 类型(8.5),重载分辨率选择构造函数。对于 直接初始化,候选函数都是 正在初始化的对象类的构造函数。 :用于 复制初始化,候选函数都是转换 该类的构造函数(12.3.1)。参数列表是 初始化程序的表达式列表或赋值表达式。
转换构造函数在§12.3.1[class.conv.ctor]中定义如下:
在没有函数说明符显式的情况下声明的构造函数 指定从其参数类型到类型的转换 它的班级。这样的构造函数称为转换构造函数。
现在,如果你相信我(为了不必引用比我的13.3更多),prvalue Derived()
将导致重载决策选择移动构造函数(取{{1} }),despite being deleted,这会导致Clang的错误。
总之,Clang在发出错误时是正确的。由于使用已删除的功能需要诊断,这是GCC中的一个错误。