c++ - 为什么这种复制初始化(带有两个隐式转换)在 GCC/Clang 中不起作用?
问题描述
请考虑以下代码:
#include <string.h>
class cstring {
public:
cstring(const char* str) : begin_(str), end_(str ? str + strlen(str) : 0)
{
}
size_t size() const
{
return (size_t)(end_ - begin_);
}
const char* data() const
{
return begin_;
}
private:
const char* begin_;
const char* end_;
};
class Name {
public:
Name(cstring str)
{
}
};
int main()
{
cstring str = "Hello World"; // OK
Name name = str; // OK
Name name2 = "James"; // error
}
Clang 会输出错误(GCC 也有类似的输出):
Source.cpp:37:10: error: no viable conversion from 'const char [6]' to 'Name'
Name name2 = "James"; // error
^ ~~~~~~~
Source.cpp:24:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from
'const char [6]' to 'const Name &' for 1st argument
class Name {
^
Source.cpp:26:5: note: candidate constructor not viable: no known conversion from 'const char [6]' to 'cstring' for 1st
argument
Name(cstring str)
^
1 error generated.
上述代码中,由于构造函数不显式,const char*
可以隐式转换为cstring
,cstring
也可以隐式转换Name
为 ;const char*
因此存在从到的转换序列Name
。那么为什么 Clang/GCC 不允许这样的复制初始化(msvc 允许这种情况)?
解决方案
gcc 和 clang 是正确的,隐式转换序列中只允许进行一次用户定义的转换。
隐式转换序列包含以下内容,按此顺序:
零个或一个标准转换序列;
零次或一次用户定义的转换;
零个或一个标准转换序列。
您可以将复制初始化更改为直接初始化as Name name2 ("James");
,其中只需要一次用户定义的转换(从const char*
to cstring
),并且转换cstring
后的作为参数传递给 to 的构造Name
函数name2
。
此外,复制初始化中的隐式转换必须直接从初始值设定项生成 T,而直接初始化需要从初始值设定项到 T 构造函数的参数的隐式转换。
推荐阅读
- reactjs - 即使应用程序关闭,如何在后台连续运行 ReactNative 应用程序
- javascript - React Context Hook 状态没有改变
- iphone - Xamarin - 物理设备部署颜色不正确
- flutter - Flutter - 在底部导航栏项目单击上打开模态底部表
- reactjs - 将插件添加到分叉的ckEditor repo'不起作用
- c# - 使用 chrome 开发工具 (C#) 在 selenium 4rc2 中添加额外的请求头
- entity-framework - 在遍历 EF Core 5 中的多个条件包含后查询任何条目
- javascript - 具有连接值的对象数组应移动到匹配值的子项
- typescript - 使用打字稿泛型类型根据对象中的兄弟字段设置函数参数类型
- python - 再次播放功能导致在刽子手游戏中被要求再次播放的循环