msvc /permissive- std::string 重载运算符“=”不明确
msvc /permissive- std::string overloaded operator '=' is ambiguous
它用 /permissive
编译,但用 /permissive-
编译失败。什么不符合要求以及如何解决?
为什么在 (2)
中没问题,但在 (4)
(3)
中失败了?
如果我删除 operator long
也可以。
如何在不更改调用站点的情况下修复它(3,4)
?
#include <string>
struct my
{
std::string myVal;
my(std::string val): myVal(val) {}
operator std::string() { return myVal; };
operator long() { return std::stol(myVal); };
};
int main()
{
struct MyStruct
{
long n = my("1223"); // (1)
std::string s = my("ascas"); // (2)
} str;
str.s = my("ascas"); // (3)
str.n = my("1223"); // (4)
}
错误信息
error C2593: 'operator =' is ambiguous
xstring(2667): note: could be 'std::basic_string<...> &std::basic_string<...>::operator =(const _Elem)'
with
[
_Elem=char
]
xstring(2648): note: or 'std::basic_string<...> &std::basic_string<...>::operator =(const std::basic_string<...> &)'
xstring(2453): note: or 'std::basic_string<...> &std::basic_string<...>::operator =(std::basic_string<...> &&) noexcept(<expr>)'
Source1.cpp(17): note: while trying to match the argument list '(std::string, my)'
我想你的意思是 它在 (2) 中很好,但在 (3) 中失败
注意 #2 是初始化,调用 constructor of std::string
; the #3 is assignment, which calls the assignment operator of std::string
。它们是不同的东西。
赋值运算符的调用不明确,因为 std::string
的赋值运算符有一个重载 char
,它可以从 long
隐式转换(这是标准转换) ,然后导致歧义(编译器抱怨赋值运算符采用 std::string
)。 implicit conversion sequence contain one user-defined conversion (from my
to std::string
or long
), they have the same rank in onverload resolution.
构造函数的调用没问题,因为它没有这样的重载(取char
)。
问题是在案例 #2 中使用了构造函数,而在案例 #3 中使用了赋值运算符。
赋值运算符重载如
basic_string& operator=(charT c);
但是没有构造函数只接受一个charT
类型的参数
因此对于案例 #2,使用了用户定义的转换运算符
operator std::string() { return myVal; };
然后是构造函数
basic_string(basic_string&& str) noexcept;
在案例 #3 中,有两种可能性。
第一个是调用转换运算符
operator std::string() { return myVal; };
然后是赋值运算符
basic_string& operator=(basic_string&& str)
而第二个是调用转换运算符
operator long() { return std::stol(myVal); };
然后是赋值运算符
basic_string& operator=(charT c);
值得注意的是以下附加案例。
如果你会写
str.s = { my("ascas") };
那就不会有歧义了。编译器将 select 接受 std::initializer_list 的运算符。即它将 select 赋值运算符
basic_string& operator=(initializer_list<charT>);
在这种情况下,将使用转换运算符
operator long() { return std::stol(myVal); };
但由于字符串"ascas"
无法转换为long类型,会出现运行时错误
terminate called after throwing an instance of 'std::invalid_argument'
what(): stol
来自莫斯科的弗拉德回答有很好的解释。但是没有解决办法。
这里使用的是 SFINAE
template<typename T = long, typename = std::enable_if_t<
std::is_same_v<T, long> || std::is_same_v<T, int>>>
operator T() const
{
return l();
}
operator std::string() const
{
return s();
}
它用 /permissive
编译,但用 /permissive-
编译失败。什么不符合要求以及如何解决?
为什么在 (2)
中没问题,但在 (4)
(3)
中失败了?
如果我删除 operator long
也可以。
如何在不更改调用站点的情况下修复它(3,4)
?
#include <string>
struct my
{
std::string myVal;
my(std::string val): myVal(val) {}
operator std::string() { return myVal; };
operator long() { return std::stol(myVal); };
};
int main()
{
struct MyStruct
{
long n = my("1223"); // (1)
std::string s = my("ascas"); // (2)
} str;
str.s = my("ascas"); // (3)
str.n = my("1223"); // (4)
}
错误信息
error C2593: 'operator =' is ambiguous
xstring(2667): note: could be 'std::basic_string<...> &std::basic_string<...>::operator =(const _Elem)'
with
[
_Elem=char
]
xstring(2648): note: or 'std::basic_string<...> &std::basic_string<...>::operator =(const std::basic_string<...> &)'
xstring(2453): note: or 'std::basic_string<...> &std::basic_string<...>::operator =(std::basic_string<...> &&) noexcept(<expr>)'
Source1.cpp(17): note: while trying to match the argument list '(std::string, my)'
我想你的意思是 它在 (2) 中很好,但在 (3) 中失败
注意 #2 是初始化,调用 constructor of std::string
; the #3 is assignment, which calls the assignment operator of std::string
。它们是不同的东西。
赋值运算符的调用不明确,因为 std::string
的赋值运算符有一个重载 char
,它可以从 long
隐式转换(这是标准转换) ,然后导致歧义(编译器抱怨赋值运算符采用 std::string
)。 implicit conversion sequence contain one user-defined conversion (from my
to std::string
or long
), they have the same rank in onverload resolution.
构造函数的调用没问题,因为它没有这样的重载(取char
)。
问题是在案例 #2 中使用了构造函数,而在案例 #3 中使用了赋值运算符。
赋值运算符重载如
basic_string& operator=(charT c);
但是没有构造函数只接受一个charT
因此对于案例 #2,使用了用户定义的转换运算符
operator std::string() { return myVal; };
然后是构造函数
basic_string(basic_string&& str) noexcept;
在案例 #3 中,有两种可能性。
第一个是调用转换运算符
operator std::string() { return myVal; };
然后是赋值运算符
basic_string& operator=(basic_string&& str)
而第二个是调用转换运算符
operator long() { return std::stol(myVal); };
然后是赋值运算符
basic_string& operator=(charT c);
值得注意的是以下附加案例。
如果你会写
str.s = { my("ascas") };
那就不会有歧义了。编译器将 select 接受 std::initializer_list 的运算符。即它将 select 赋值运算符
basic_string& operator=(initializer_list<charT>);
在这种情况下,将使用转换运算符
operator long() { return std::stol(myVal); };
但由于字符串"ascas"
无法转换为long类型,会出现运行时错误
terminate called after throwing an instance of 'std::invalid_argument'
what(): stol
来自莫斯科的弗拉德回答有很好的解释。但是没有解决办法。 这里使用的是 SFINAE
template<typename T = long, typename = std::enable_if_t<
std::is_same_v<T, long> || std::is_same_v<T, int>>>
operator T() const
{
return l();
}
operator std::string() const
{
return s();
}