在MSVC中,据说存在模糊的显式转换操作符,而在gcc或clang中则不存在。

huangapple go评论66阅读模式
英文:

Supposedly ambiguous explicit conversion operator in MSVC, not in gcc or clang

问题

以下是代码部分的中文翻译:

class String {
public:
    String(std::string_view s) : str{s} {}
    operator std::string() const {
        return str;
    }
    operator const char*() const {
        return str.c_str();
    }
private:
    std::string str;
};


int main()
{
    static_assert(std::is_convertible_v<String, std::string>);
    String s("Hello World");
    auto x = static_cast<std::string>(s);
    return 0;
}

MSVC 告诉我,对 std::string 的静态转换是不明确的,而 clang 和 gcc 没有这个问题:https://godbolt.org/z/7de5YvTno

<source>(20): error C2440: 'static_cast': 无法从 'String' 转换为 'std::string'
<source>(20): note: 源类型可能不存在构造函数,或者构造函数重载存在歧义
Compiler returned: 2

哪个编译器是正确的?

作为一个后续问题:我可以通过将转换操作标记为显式来解决这个歧义。但是然后 std::is_convertible_v&lt;String, std::string&gt; 返回 false。是否有一个类型特性 is_explicitly_convertibleis_static_castible 或类似的特性?

PS:我知道最简单且最干净的解决方法是有一个非复制的转换操作到 const std::string&,但我仍然想了解为什么 MSVC 拒绝了这段代码。

英文:

Consider the following class that implements a user-conversion to std::string and const char*:

class String {
public:
    String(std::string_view s) : str{s} {}
    operator std::string() const {
        return str;
    }
    operator const char*() const {
        return str.c_str();
    }
private:
    std::string str;
};


int main()
{
    static_assert(std::is_convertible_v&lt;String, std::string&gt;);
    String s(&quot;Hello World&quot;);
    auto x = static_cast&lt;std::string&gt;(s);
    return 0;
}

MSVC tells me that static_casting to std::string is ambiguous, while clang and gcc do not: https://godbolt.org/z/7de5YvTno

&lt;source&gt;(20): error C2440: &#39;static_cast&#39;: cannot convert from &#39;String&#39; to &#39;std::string&#39;
&lt;source&gt;(20): note: No constructor could take the source type, or constructor overload resolution was ambiguous
Compiler returned: 2

Which compiler is right?

As a follow-up question: I can fix the ambiguity by marking the conversion operations explicit. But then std::is_convertible_v&lt;String, std::string&gt; returns false. Is there a type trait is_explicitly_convertible or is_static_castible or similar?

PS: I know the simplest and cleanest solution would be to have a non-copying conversion operator to const std::string&amp;, but I still want to understand why MSVC rejects the code.

答案1

得分: 3

这是CWG2327

按照书写,static_cast 指定的直接初始化严格考虑了 std::string构造函数,而 String 参数需要无法比较的用户定义转换来满足 const char* 的移动构造函数或转换构造函数。需要注意的是,无论可用的转换函数集是什么,都必须调用构造函数,这就是该问题中提到的拷贝省略遗漏的地方。

意图是同时考虑x的实际初始化的构造函数和转换函数。这在某种程度上有点不同寻常,因为std::stringString的成员函数在同一个重载集中,但这解决了歧义,因为调用operator std::string 对于(隐含的对象)参数来说是一个完全匹配,并且它允许x成为常规C++17意义上该函数的返回值。

MSVC正在按照标准的规定实现,而GCC和Clang正在实现(类似于)预期的解决方案。

std::is_constructible 大致上是你也提到的直接初始化特性。)

英文:

This is CWG2327.

As written, the direct-initialization specified for static_cast strictly considers constructors for std::string, and the String argument requires incomparable user-defined conversions to satisfy either the move constructor or the converting constructor from const char*. Note that, regardless of the set of conversion functions available, a constructor must be called, which is the missed copy elision mentioned in the issue.

The intent is that constructors and conversion functions are simultaneously considered for the actual initialization of x. This is a bit unusual in that member functions of std::string and String are in the same overload set, but it resolves the ambiguity because calling operator std::string is an exact match for the (implied object) argument, and it allows x to be the return value from that function in the ordinary C++17 sense.

MSVC is implementing the standard as written, while GCC and Clang are implementing (something like) the intended resolution.

(std::is_constructible is more or less the direct-initialization trait you also asked about.)

huangapple
  • 本文由 发表于 2023年2月17日 23:35:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/75486299.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定