大佬教程收集整理的这篇文章主要介绍了为什么这种移动和值构造函数的组合对 MSVC 不明确,但对 C++17 及更高版本中的 Clang 和 GCC 不明确,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
我有以下代码
struct R {
int i_ = 8;
R() = default;
R(R const& o) = default;
R(R&& o) = default;
R(int i) : i_(i) {}
operator int() const { return i_; }
};
struct S {
R i_;
operator R() const { return i_; }
operator int() const { return static_cast<int>(i_); }
};
int main() {
S s;
R r0(s);
R r = static_cast<R>(s);
float af[] = {1,2,3};
float f1 = af[s];
float f2 = af[r];
}
在 C++ 17 和 C++ 20(不适用于 C++
'R::r': ambiguous call to overloaded function
note: Could be 'R::r(R &&)'
note: or 'R::r(int)'
在所有可用标准的 MSVC 中。
我试图通过比较 MSVC、Clang 和 GCC 来找到语言一致性的差异,并且还尝试了 /permissive- 用于 MSVC,但还没有找到任何解释.
R&&
和 int i
构造函数或将强制转换标记为显式 operator int()
的情况下为 MSVC 编译?此处是 a rather crowded godbolt,包括可能的解决方法。
这是 CWG 2327,目前没有解决方案,但 gcc 和 clang 似乎做了“正确的事”。问题如下:
考虑一个例子:
struct Cat {};
struct Dog { operator Cat(); };
Dog d;
Cat c(d);
这将转到 9.4 [dcl.init] 项目符号 17.6.2:
否则,如果初始化是直接初始化,或者是复制初始化,其中源类型的 cv 非限定版本与目标类的类相同,或者是目标类的派生类,则构造函数为经过考虑的。枚举适用的构造函数(12.2.2.4 [over.match.ctor]),通过重载决议(12.2 [over.match])选择最好的构造函数。调用如此选择的构造函数来初始化对象,并将初始化表达式或表达式列表作为其参数。如果没有构造函数应用,或者重载解析不明确,则初始化格式错误。
重载解析选择Cat
的移动构造函数。根据 9.4.4 [dcl.init.ref] bullet 5.2.1.2,初始化构造函数的 Cat&&
参数会产生一个临时参数。这排除了这种情况下复制省略的可能性。
这似乎是对保证复制省略的措辞更改的疏忽。在这种情况下,我们大概应该同时考虑构造函数和转换函数,就像复制初始化一样,但我们需要确保不会引入任何新问题或歧义。
这里的情况类似,只是更复杂。无论是:
R r0(s);
R r = static_cast<R>(s);
我们有一个来自 s
的转换函数,它给出了一个纯右值 R
,这是比我们可以使用的任何其他路径更好的路径——无论是通过 R
的移动构造函数或 R(int)
。但我们只是没有规定我们应该这样做。
gcc 和 clang 似乎在 C++17 或更高版本(我们保证复制省略)上实现了所需的行为,尽管没有任何关于所需行为的措辞。另一方面,msvc 似乎遵循指定的规则(我认为确实将这种情况指定为模棱两可)。
以上是大佬教程为你收集整理的为什么这种移动和值构造函数的组合对 MSVC 不明确,但对 C++17 及更高版本中的 Clang 和 GCC 不明确全部内容,希望文章能够帮你解决为什么这种移动和值构造函数的组合对 MSVC 不明确,但对 C++17 及更高版本中的 Clang 和 GCC 不明确所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。