在查看this问题的时候,我用铿锵声试了一下,陷入了一种奇怪的境地。以下示例:
#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
中的copy ctor。
答案 0 :(得分:19)
简化为:
struct A {};
struct B { operator const A(); };
B b;
A a(b);
这是direct-initialization destination type class type A
,因此枚举A
candidate constructors,选择A的所有构造函数(包括隐式定义的副本和移动构造函数)并通过overload resolution比较direct-initialization of a class object。首先评估构造函数的viability,这意味着尝试从b
(左值B
)构造implicit conversion sequence到他们的参数。由于参数是引用(A const&
或A&&
),因此我们必须执行reference initialization。我们可以A const&
b
b
A const
,因为A const
可以转换为右值A const
,A&&
(目标参考的类型)和b
(目标函数的返回类型)是initialize a reference(因为它们是相同的cv限定类型);实际上,这是一个reference-compatible。我们无法从A&&
direct reference binding开始A const
而不是A::A(A const&)
初始化引用A
。所以struct A { A(A const&) = default; };
struct B { operator const A(); };
B b;
A a(b);
是唯一可行的构造函数并被选中。
据报道,已多次叮叮has lesser cv-qualification 1 2,但遗憾的是没有被提起。
所有其他主要编译器(gcc,ICC,MSVC)都正确编译代码。
有趣的是,正如所讨论的3 clang在C ++ 03模式下正确编译代码。如果我们通过抑制其移动构造函数强制A&& a = b;
成为“C ++ 03样式”类型,则clang将编译生成的代码:
{{1}}
这表明也许clang被移动构造函数搞糊涂了。它不应该,因为移动构造函数不可行; {{1}}无效。