为什么这个复制初始化(有两个隐式转换)在 GCC/Clang 中不起作用?
Why this copy-initialization (with two implicit conversions) does not work in 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是正确的,implicit conversion sequence中只允许一个用户自定义转换。
Implicit conversion sequence consists of the following, in this order:
zero or one standard conversion sequence;
zero or one user-defined conversion;
zero or one standard conversion sequence.
您可以将 copy-initialization to direct-initialization 更改为 Name name2 ("James");
,其中只需要一个用户定义的转换(从 const char*
到 cstring
),转换后的 cstring
作为参数传递给 Name
的构造函数以构造 name2
.
In addition, the implicit conversion in copy-initialization must produce T directly from the initializer, while, e.g. direct-initialization expects an implicit conversion from the initializer to an argument of T's constructor.
请考虑以下代码:
#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是正确的,implicit conversion sequence中只允许一个用户自定义转换。
Implicit conversion sequence consists of the following, in this order:
zero or one standard conversion sequence;
zero or one user-defined conversion;
zero or one standard conversion sequence.
您可以将 copy-initialization to direct-initialization 更改为 Name name2 ("James");
,其中只需要一个用户定义的转换(从 const char*
到 cstring
),转换后的 cstring
作为参数传递给 Name
的构造函数以构造 name2
.
In addition, the implicit conversion in copy-initialization must produce T directly from the initializer, while, e.g. direct-initialization expects an implicit conversion from the initializer to an argument of T's constructor.