c++ - 防止函數使用const std:: string&接受0
implicit-conversion (2)
值一千字:
#include<string>
#include<iostream>
class SayWhat {
public:
SayWhat& operator[](const std::string& s) {
std::cout<<"here\n"; // To make sure we fail on function entry
std::cout<<s<<"\n";
return *this;
}
};
int main() {
SayWhat ohNo;
// ohNo[1]; // Does not compile. Logic prevails.
ohNo[0]; // you didn't! this compiles.
return 0;
}
將數字0傳遞給接受字符串的方括號運算符時,編譯器不會抱怨。 相反,它會在輸入以下方法之前編譯並失敗:
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid
以供參考:
> g++ -std=c++17 -O3 -Wall -Werror -pedantic test.cpp -o test && ./test
> g++ --version
gcc version 7.3.1 20180303 (Red Hat 7.3.1-5) (GCC)
我猜
編譯器隱式使用
std::string(0)
構造函數輸入該方法,由於沒有充分的理由,這會產生相同的問題(谷歌上述錯誤)。
題
無論如何,有沒有在類方面解決此問題,因此API用戶感覺不到這一點,並且在編譯時檢測到錯誤?
也就是說,添加重載
void operator[](size_t t) {
throw std::runtime_error("don't");
}
不是一個好的解決方案。
一種選擇是聲明一個
operator[]()
的
private
重載,該重載接受一個整數參數,而不定義它。
此選項可與所有C ++標準(1998年以後)一起使用,不同於
void operator[](std::nullptr_t) = delete
類的選項在C ++ 11中有效。
將
operator[]()
ohNo[0]
private
成員會在示例
ohNo[0]
上引起可診斷的錯誤,除非該表達式由成員函數或類的
friend
使用。
如果從成員函數或類的
friend
使用該表達式,則將編譯代碼,但是-由於未定義函數-通常,構建將失敗(例如,由於未定義函數而導致的鏈接器錯誤)。
std::string(0)
有效的原因是由於
0
是空指針常量。
因此,它與採用指針的構造函數匹配。
然後,它違反了一個前提條件,即不能將空指針傳遞給
std::string
。
只有立即數
0
會被解釋為空指針常量,如果它是
int
的運行時值,那麼您就不會有這個問題(因為過載解析會改為查找
int
轉換)。
文字
1
也不是問題,因為
1
不是空指針常量。
由於這是一個編譯時問題(字面無效值),因此您可以在編譯時捕獲它。 添加此形式的重載:
void operator[](std::nullptr_t) = delete;
std::nullptr_t
是
nullptr
的類型。
並且它將匹配
任何
空指針常量,可以是
0ULL
或
nullptr
。
並且由於刪除了該函數,因此在重載解析期間將導致編譯時錯誤。