[英]Function pointer which accepts both with and without noexcept
我有一些實用程序代碼,多年來我一直在使用這些代碼來安全地調用 ctype 系列函數,它看起來像這樣:
template<int (&F)(int)>
int safe_ctype(unsigned char c) {
return F(c);
}
並且是這樣使用的:
int r = safe_ctype<std::isspace>(ch);
這個想法是它為您處理將輸入int
轉換為無符號值的需要,以防止未定義的行為。 這個 function 的細節有點無關緊要。 這是我的問題:
現在在 C++17 及更高版本中, noexcept
是類型系統的一部分,這是一個編譯錯誤! 因為所有 ctype 函數現在都是noexcept
。
編輯:上面的句子是不正確的。 ctype 系列函數不是noexcept
。 但是,我在 gcc < 11.2 中遇到編譯器錯誤。 https://godbolt.org/z/cTq94q5xE
該代碼可以在所有 3 個主要編譯器的最新版本中按預期工作(盡管由於這些函數不可尋址,技術上不允許這樣做)。
我當然可以將我的 function 更改為如下所示:
template<int (&F)(int) noexcept>
int safe_ctype(unsigned char c) noexcept {
return F(c);
}
但是現在編譯為 C++11 或 C++14 時它不起作用。 所以我最終不得不做這樣的事情:
#if __cplusplus >= 201703L
template<int (&F)(int) noexcept>
int safe_ctype(unsigned char c) noexcept {
return F(c);
}
#else
template<int (&F)(int)>
int safe_ctype(unsigned char c) {
return F(c);
}
#endif
對於這樣一個簡單的任務,這變得越來越復雜。 那么有沒有辦法制作 function 指針:
?
我試着做這樣的事情:
template<class F>
int safe_ctype(unsigned char c) noexcept {
return F(c);
}
希望它會接受“任何東西”,但遺憾的是,沒有 go。
想法?
現在在 C++17 及更高版本中, noexcept 是類型系統的一部分,這是一個編譯錯誤。 因為現在所有的 ctype 函數都是 noexcept。
這不是編譯錯誤。 指向 noexcept 函數的指針可以隱式轉換為指向潛在拋出函數的指針,因此接受指向潛在拋出函數的指針的模板適用於潛在拋出函數和 noexcept 函數。 唯一需要注意的是,noexceptedness 信息會丟失,並且可能不會用於優化目的。
因此,原始解同時滿足第 1 點和第 2 點。
評論中指出的另一個問題是您打算使用的標准庫函數( std::isspace
)未指定為“可尋址”。 因此,由於形成了指向它們的指針,程序的行為是未指定的(可能是格式錯誤的)。
要包裝此類可調用對象,您可以使用 lambda 而不是 function 指針。 但這會使模板本身過時,因為您可以直接更改 lambda 的參數類型:
auto safe_isspace = [](unsigned char c){ return std::isspace(c); };
int r = safe_isspace(ch);
雖然我們不再需要將其傳遞到模板中,但同樣可以使用普通的 function 來實現:
int // or bool?
safe_isspace(unsigned char c) noexcept // ...
由於這涉及多個功能的一些相同樣板,因此這是元編程的良好候選者。
因為現在所有的 ctype 函數都是 noexcept。
這是不真實的。 C++17 沒有向通過 C++ c*
頭文件訪問的任何 C 庫函數添加noexcept
。 您可以在此處看到所有 C++ function 聲明不包含noexcept
。 並且不允許標准庫實現將非noexcept
函數noexcept
。
其次,即使它是noexcept
,也可以將noexcept
function 指針轉換為拋出的 function 指針(但不能反過來)。 所以你的代碼編譯。
但最重要的是,C++20 清楚地表明,除非特別說明,否則不允許為任何 C++ 標准庫 function 獲取 function 指針。 C++標准庫中可尋址的函數很少。
所以在 C++20 中,你的代碼會產生 UB。 如果您希望您的代碼適用於所有語言版本,您只需要為 cctype 函數編寫包裝器。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.