提问人:Sedenion 提问时间:2/7/2022 最后编辑:cigienSedenion 更新时间:2/7/2022 访问量:650
基类中模板化构造函数的 clang/gcc 和 MSVC 之间的不同结果
Different results between clang/gcc and MSVC for templated constructor in base class
问:
我偶然发现了下面一段代码。该案例在 MSVC 上产生的结果与在 clang 或 gcc 上产生的结果不同。也就是说,clang 13 和 gcc 11.2 调用 的复制构造函数,而 MSVC v19.29 调用模板化构造函数。我正在使用 C++17。"DerivedFoo"
Foo
考虑到所有编译器都同意调用模板化构造函数的非派生情况 (),我认为这是 clang 和 gcc 中的一个错误,并且 MSVC 是正确的吗?还是我解释错了,clang/gcc 是正确的?谁能阐明可能发生的事情?"Foo"
代码 (https://godbolt.org/z/bbjasrraj):
#include <iostream>
using namespace std;
struct Foo {
Foo() {
cout << "\tFoo default constructor\n";
}
Foo(Foo const &) { cout << "\tFoo COPY constructor\n";
}
Foo(Foo &&) {
cout << "\tFoo move constructor\n";
}
template <class U>
Foo(U &&) {
cout << "\tFoo TEMPLATED constructor\n";
}
};
struct DerivedFoo : Foo {
using Foo::Foo;
};
int main() {
cout << "Foo:\n";
Foo f1;
Foo f2(f1);
cout << "\nConst Foo:\n";
Foo const cf1;
Foo cf2(cf1);
cout << "\nDerivedFoo:\n";
DerivedFoo d1;
DerivedFoo d2(d1);
cout << "\nConst DerivedFoo:\n";
DerivedFoo const cd1;
DerivedFoo cd2(cd1);
}
clang 和 gcc 的结果:
Foo:
Foo default constructor
Foo TEMPLATED constructor
Const Foo:
Foo default constructor
Foo COPY constructor
DerivedFoo:
Foo default constructor
Foo COPY constructor <<<<< This is different
Const DerivedFoo:
Foo default constructor
Foo COPY constructor
MSVC 的结果:
Foo:
Foo default constructor
Foo TEMPLATED constructor
Const Foo:
Foo default constructor
Foo COPY constructor
DerivedFoo:
Foo default constructor
Foo TEMPLATED constructor <<<<< This is different
Const DerivedFoo:
Foo default constructor
Foo COPY constructor
答:
构造函数模板通常比复制构造函数更适合带有类型参数的构造函数调用,这是正确的,因为它不需要转换。DerivedFoo&
Foo&
const
但是,[over.match.funcs.general]/8 本质上(几乎)用更一般的措辞说,具有移动或复制构造函数形式的继承构造函数被排除在重载解析之外,即使它是从构造函数模板中实例化的。因此,将不考虑模板构造函数。
因此,隐式复制构造函数将通过重载解析来选择DerivedFoo
DerivedFoo d2(d1);
这将调用构造基类子对象。Foo(Foo const &);
这个措辞是CWG 2356的结果,在C++17之后得到了解决,但我认为它也应该是针对旧版本的缺陷报告。(不过我真的不知道。
所以 GCC 和 Clang 在这里是正确的。另请注意,如果使用一致性模式 (),则 MSVC 的行为也与版本 19.30 起的缺陷报告一致。/permissive-
评论
DerivedFoo d2(d1);
Foo
Foo
std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<U>>, Foo>>
std::optional
DerivedFoo d2(d1)
enable_if
DerivedFoo
Foo
评论
/permissive-