簡體   English   中英

Function 指針,它接受有和沒有 noexcept

[英]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 指針:

  1. 適用於 C++11 - C++20
  2. 在 C++17+ 中同時接受 noexcept 和 non-noexcept

?

我試着做這樣的事情:

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.

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