这是一个铿锵的bug还是我不了解的关于C++的东西?

Rud*_*lis 19 c++ gcc clang language-lawyer

在看这个问题时,我用铿锵声试了一下,陷入了一种奇怪的境地.以下示例:

#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;
}
Run Code Online (Sandbox Code Playgroud)

使用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.
Run Code Online (Sandbox Code Playgroud)

但是我不明白为什么编译器不能使用copy ctor std::string.

eca*_*mur 19

简化:

struct A {};
struct B { operator const A(); };
B b;
A a(b);
Run Code Online (Sandbox Code Playgroud)

这是直接初始化目标类型的类类型 A,所以候选构造A列举,选择A的所有构造函数(包括隐式定义的复制和移动的构造),并通过比较重载解析一个类对象的直接初始化.首先评估构造函数的可行性,这意味着尝试构造从(左值)到其参数的隐式转换序列.由于参数是引用(或),我们必须执行引用初始化.我们可以初始化一个引用,因为可以转换为rvalue ,并且(目标引用的类型)和(目标函数的返回类型)是引用兼容的(因为它们是相同的cv限定类型); 实际上,这是一个直接的参考绑定.我们无法初始化引用,因为具有较小的cv资格而不是.因此是唯一可行的构造函数并被选中.bBA const&A&& A const&bbA constA constA constA&&bA&& A constA::A(A const&)

据报道,这已经多次铿锵1 2 3但遗憾的是没有被捡起来.

所有其他主要编译器(gcc,ICC,MSVC)正确编译代码.

有趣的是,正如这里讨论的那样, clang在C++ 03模式下正确编译代码.如果我们A通过抑制其移动构造函数强制成为"C++ 03样式"类型,则clang将编译生成的代码:

struct A { A(A const&) = default; };
struct B { operator const A(); };
B b;
A a(b);
Run Code Online (Sandbox Code Playgroud)

这表明也许clang被移动构造函数搞糊涂了.它不应该,因为移动构造函数不可行; A&& a = b;是无效的.