8

它编译/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)'
4

3 回答 3

7

我想你的意思是它在(2)中很好,但在(3)中失败了

注意 #2 是初始化,它调用 ; 的构造函数std::string。#3 是赋值,它调用 的赋值运算符std::string。它们是不同的东西。

赋值运算符的调用是模棱两可的,因为赋值运算符std::string有一个重载char,可以从隐式转换long(这是一个标准转换),然后导致模棱两可(赋值运算符采用std::string,正如编译器抱怨的那样)。两个隐式转换序列都包含一个用户定义的转换(从mystd::stringlong),它们在onverload 分辨率中具有相同的等级。

构造函数的调用很好,因为它没有这样的重载(接受char)。

于 2019-09-06T11:54:10.600 回答
3

问题是在案例#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") };

那么就不会有歧义了。编译器将选择接受 std::initializer_list 的运算符。那就是它将选择赋值运算符

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
于 2019-09-06T11:55:56.383 回答
0

来自莫斯科的弗拉德回答有一个很好的解释。但没有解决办法。这里使用的是 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();
}
于 2020-10-13T16:41:26.980 回答