簡體   English   中英

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 是初始化,它調用了std::string構造函數 #3 是賦值,它調用std::string賦值運算符 它們是不同的東西。

賦值運算符的調用是模棱兩可的,因為std::string的賦值運算符有一個采用char的重載,它可以從long隱式轉換(這是一個標准轉換),然后導致歧義(賦值運算符采用std::string ,正如編譯器所抱怨的那樣)。 兩個 隱式轉換序列都包含一個用戶定義的轉換(從mystd::stringlong ),它們在onverload resolution 中具有相同的等級。

構造函數的調用很好,因為它沒有這樣的重載(采用char )。

問題是在#2 的情況下使用了構造函數,而在#3 的情況下使用了賦值運算符。

賦值運算符像重載一樣

basic_string& operator=(charT c);

但是沒有構造函數只接受一個charT類型的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

來自莫斯科的弗拉德回答有一個很好的解釋。 但是沒有解決辦法。 這里使用的是 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();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM