我正在開發用于宣告性 UI 構建的模板工具包。我按預期在 Windows 上編譯了模板,但 GCC/clang 編譯器對我的 SFINAE 作業提出了問題。
我使用 Qt 作為基礎,我希望在包裝器結構中包含 QLayout 和 QWidget 專案,同時根據它們代表的物件切換包裝器的開/關功能。
它們都源自 QObject,它提供了大量的共同點,但我想包括它們的擴展功能。
在 MSVC 上,以下效果非常好
// let cls be the input subclass of QWidget or
// QLayout which is passed to the owning wrapper template
template<typename = std::enable_if<std::is_base_of<QWidget, cls>::value == true>>
Wrapper &style() {
cast()->setStyleSheet(stylesheet);
return *this;
}
但是 GCC/clang 不同意。我試過使用類似的東西:
template<typename Empty = void,
typename = typename std::enable_if<
std::is_base_of<QWidget, cls>::value, Empty
>::type
>
Wrapper &style(const QString &stylesheet) {
cast()->setStyleSheet(stylesheet);
return *this;
}
但是仍然收到一個錯誤,指出 QLayout 子類沒有 member setStyleSheet。雖然沒有,但我希望編譯器可以像在 MSVC 中那樣完全跳過該函式。
我假設我對 SFINAE 系統有誤解,需要調整我的模板宣告,或者只是把它吸起來并拆分兩個專案并重復代碼。
編輯:
問題復制:https : //gcc.godbolt.org/z/oGzsKhrn4
最高位只是 Qt 物件的最小表示,它代表了我所追求的相同基本結構,您幾乎可以忽略它們。
宏是為了簡化每個類所需的模板。如果不出意外,我總是可以分解它并添加額外的宏來填充 QWidget 與 QLayout 功能,我只是喜歡它在 Windows 中的干凈程度。
uj5u.com熱心網友回復:
在您的示例中,style函式體的行為不依賴于其模板引數,編譯器可以檢查其正確性。我想這是[temp.res#general] 中的標準允許的:
程式格式錯誤,無需診斷,如果:
...
— 緊接其定義的模板的假設實體將由于不依賴模板引數的構造而格式錯誤,
...
但是,您可以QVBoxLayout像以前一樣創建模板默認引數(而不是Empty),但使主體也依賴于此引數:
template<typename QVBoxLayout_ = QVBoxLayout,
typename = typename std::enable_if<
std::is_base_of<QWidget, QVBoxLayout_>::value, void
>::type
>
VLayout &style(const QString &stylesheet) {
QVBoxLayout_::cast()->setStyleSheet(stylesheet); // "shouldn't matter"
return *this;
}
但在這種情況下,我們有一個問題。有些用戶可能不小心傳遞了這個引數,SFINAE 會被破壞,所以我提出以下修復。添加一個引數包作為第一個函式模板引數。它會“吃掉”所有意外傳遞的引數,因此用戶將無法覆寫默認引數:
template<typename..., typename QVBoxLayout_ = QVBoxLayout...
而且,當然,您可以添加一個斷言,即用戶不會無意中嘗試覆寫這些引數。總之:
template<typename... ParameterGuard_,
typename QVBoxLayout_ = QVBoxLayout,
typename = typename std::enable_if<
std::is_base_of<QWidget, QVBoxLayout_>::value, void
>::type
>
VLayout &style(const QString &stylesheet) {
static_assert(sizeof...(ParameterGuard_) == 0,
"This function template is not intended to accept template parameters");
QVBoxLayout_::cast()->setStyleSheet(stylesheet); // "shouldn't matter"
return *this;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/368733.html
