【问题标题】:Is this a clang bug or something I don't know about C++?这是一个clang错误还是我不了解C ++的东西?
【发布时间】:2018-01-09 09:04:47
【问题描述】:

在查看this 问题时,我用clang 进行了尝试,但遇到了一个奇怪的情况。下面的例子:

#include <string>

class ACP
{
public:
    ACP() {}
    operator const std::string() const  { return std::string(); }
    // operator std::string() const  { return std::string(); } <-- makes clang happy
};

void test()
{
   const ACP acp;
   auto a = (std::string)acp;
}

使用 gcc 在 coliru 上编译良好,但由于 clang 失败。至少我认为这个例子没有问题 - 这是 clang 中的一个错误,还是有一个规则可以实际解释 clang 错误并且 gcc 是错误的?

clang 的错误如下所示:

clang -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp:13:26: error: no viable conversion from 'const ACP' to 'std::__cxx11::basic_string<char>'
   auto a = (std::string)acp;
                         ^~~
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/7.1.0/../../../../include/c++/7.1.0/bits/basic_string.h:421:7: note: candidate constructor not viable: no known conversion from 'const ACP' to 'const std::__cxx11::basic_string<char> &' for 1st argument
      basic_string(const basic_string& __str)
      ^
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/7.1.0/../../../../include/c++/7.1.0/bits/basic_string.h:493:7: note: candidate constructor not viable: no known conversion from 'const ACP' to 'const char *' for 1st argument
      basic_string(const _CharT* __s, const _Alloc& __a = _Alloc())
      ^
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/7.1.0/../../../../include/c++/7.1.0/bits/basic_string.h:515:7: note: candidate constructor not viable: no known conversion from 'const ACP' to 'std::__cxx11::basic_string<char> &&' for 1st argument
      basic_string(basic_string&& __str) noexcept
      ^
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/7.1.0/../../../../include/c++/7.1.0/bits/basic_string.h:542:7: note: candidate constructor not viable: no known conversion from 'const ACP' to 'initializer_list<char>' for 1st argument
      basic_string(initializer_list<_CharT> __l, const _Alloc& __a = _Alloc())
      ^
main.cpp:7:5: note: candidate function
    operator const std::string() const  { return std::string(); }
    ^
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/7.1.0/../../../../include/c++/7.1.0/bits/basic_string.h:515:35: note: passing argument to parameter '__str' here
      basic_string(basic_string&& __str) noexcept
                                  ^
1 error generated.

但是我不明白为什么编译器不能使用来自 std::string 的复制 ctor。

【问题讨论】:

  • clang 在我看来有点可疑,但返回 const 对象可能是您的逻辑错误或误解。您确定不想返回对 const 字符串的引用吗?
  • std::string a = acp; 而不是 auto a = (std::string)acp; 在 clang 中工作,如果这有任何帮助的话。
  • 其实只要在操作符前面加上explicit也让Clang开心...explicit operator const std::string() const { return std::string(); }
  • 这不是要求两个隐式的用户定义转换,而只允许一个?第一次转换ACP-&gt;const std::string,第二次转换const std::string-&gt;std::string(通过复制构造函数)
  • @RichardHodges 返回const 对象而不是非常量实际上是(曾经)Scott Meyer 推荐的做法,至少它适用于 C++03(如果我没记错的话)。

标签: c++ gcc clang language-lawyer


【解决方案1】:

简化:

struct A {};
struct B { operator const A(); };
B b;
A a(b);

这是direct-initializationdestination type class typeA,所以枚举A中的candidate constructors,选择A的所有构造函数(包括隐式定义的复制和移动构造函数)并通过overload resolution比较direct-initialization of a class object。首先,构造函数被评估为viability,这意味着尝试从b(一个左值B)构造一个implicit conversion sequence到它们的参数。由于参数是引用(A const&amp;A&amp;&amp;),我们必须执行reference initialization。我们可以将initialize a reference A const&amp;b 转换为右值A constA const(目标引用的类型)和A const(目标函数的返回类型) ) 是 reference-compatible (因为它们是相同的 cv 限定类型);事实上,这是一个direct reference binding。我们无法从b 初始化引用A&amp;&amp;,因为A&amp;&amp; has lesser cv-qualification 而不是A const。所以A::A(A const&amp;)是唯一可行的构造函数并被选中。

这个已经被clang多次举报123但遗憾的是一直没有收到。

所有其他主要编译器(gcc、ICC、MSVC)都能正确编译代码。

有趣的是,正如here clang 所讨论的,在 C++03 模式下正确编译代码。如果我们通过抑制其移动构造函数来强制 A 成为“C++03 风格”类型,clang 将编译生成的代码:

struct A { A(A const&) = default; };
struct B { operator const A(); };
B b;
A a(b);

这表明可能 clang 被移动构造函数弄糊涂了。不应该,因为移动构造函数不可行; A&amp;&amp; a = b; 无效。

【讨论】:

    猜你喜欢
    • 2020-11-25
    • 1970-01-01
    • 2015-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-13
    • 1970-01-01
    相关资源
    最近更新 更多