为什么在这里添加一个临时变量会使这个编译器错误消失?类型相同



给定以下内容:

#include <string>
class s1
{
private:
std::string storage;
public:
s1(s1 *newValue) { storage=*newValue; }
operator std::string () { return storage; }
};
class s2
{
private:
std::string storage;
public:
s2(s2 *newValue) { std::string temp=*newValue; storage=temp; }
operator std::string const () { return storage; }
};
class s3
{
private:
std::string storage;
public:
s3(s3 *newValue) { storage=*newValue; } // Compile Error here.
operator std::string const () { return storage; }
};

第一个(s1)和第二个(s2)示例编译良好;第三个示例不能...但是s2和s3应该相同,除了通过temp变量传递值。

将错误消息追逐到库代码中,我认为编译器正在尝试绑定到 s3 情况下 std::string 上的移动构造函数。

我不明白的是它为什么要这样做;为什么我可以做我对 s2 所做的,但不能做 s3 ---它们不应该在语义上相同吗?

任何人可以提供的任何启发将胜感激!

FWIW,IDE是Xcode Version 9.2(9C40b);C++变体是gnu++17。另外,这是来自Xcode的(略微编辑的)错误列表:


In file included from /Users/... big long path here... .cpp:9:
/Users/... big long path here... .hpp:77:31: error: no viable conversion from 's3' to 'std::__1::basic_string<char>'
s3(s3 *newValue) { storage=*newValue; }
^~~~~~~~~
In file included from /Users/... big long path here... .cpp:9:
In file included from /Users/... big long path here... .hpp:45:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/string:763:5: note: candidate constructor not viable: no known conversion from 's3' to 'const std::__1::basic_string<char> &' for 1st argument
basic_string(const basic_string& __str);
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/string:768:5: note: candidate constructor not viable: no known conversion from 's3' to 'std::__1::basic_string<char> &&' for 1st argument
basic_string(basic_string&& __str)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/string:778:31: note: candidate constructor not viable: no known conversion from 's3' to 'const value_type *' (aka 'const char *') for 1st argument
_LIBCPP_INLINE_VISIBILITY basic_string(const value_type* __s);
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/string:810:5: note: candidate constructor not viable: no known conversion from 's3' to 'initializer_list<value_type>' (aka 'initializer_list<char>') for 1st argument
basic_string(initializer_list<value_type> __il);
^
In file included from /Users/... big long path here... .cpp:9:
/Users/... big long path here... .hpp:78:4: note: candidate function
operator std::string const () { return storage; }
^
In file included from /Users/... big long path here... .cpp:9:
In file included from /Users/... big long path here... .hpp:45:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/string:829:44: note: passing argument to parameter '__str' here
basic_string& operator=(basic_string&& __str)
^
1 error generated.

问题 CWG 1604 的解决方案使得使用可转换为const T右值的初始值设定项直接初始化类类型T的右值引用的格式不正确,但仍然可以形成隐式转换序列,因为分辨率不会更改隐式转换序列的相关部分。

因此,在您的s3示例中,根据 [over.ics.rank]/3.2.3,在重载解析期间排名string::operator=(const string&)string::operator=(string&&)

标准转换序列

S1 比标准转换序列 S2 更好的转换序列,如果

  • S1 和 S2 是引用绑定,
  • 两者都不引用在没有 ref 限定符的情况下声明的非静态成员函数的隐式对象参数,S1 将右值引用绑定到右值,S2 绑定左值引用

编译器最后选择string::operator=(string&&),因此在其参数的实际初始化发生时会导致错误。

在您的s2示例中,语义是复制初始化而不是选择正确的赋值运算符,并且没有引用绑定。所以一切都很好。

感谢 T.C. 在本次讨论中指出这已经是 CWG 2077 的起草问题。

我会推测(但它只是你所看到的):

s2(s2 *newValue) { std::string temp=*newValue; storage=temp; }

可由编译器通过隐式强制转换自动完成。

其中:

s3(s3 *newValue) { storage=*newValue; }

不能。

括号中的第一个位置(*newValue),看看它是否误解了编译器中的意图。第二次尝试执行显式强制转换:

s3(s3 *newValue) { storage=((std::string)(*newValue)); }

如果这些都不起作用,我将不得不克服这是一个编译器问题。

相关内容

最新更新