[英]compiler differences when using std::enable_if in return type of templated member function
我試圖為struct Node
中的一個方法定義兩個“重載”,根據結構模板參數調用不同的行為。
我知道我可以使用其他方法(例如if constexpr
或其他方法)。
我擔心的是,我“欺騙”了 gcc 9.0.0 實驗 20180919 來編譯它,但是 wandbox(下面的 permlink)中可用的所有其他最新編譯器都沒有。 我想 gcc8 和 clang6/7 在這里做正確的事?
謝謝你的幫助!
#include <iostream>
#include <type_traits>
enum laziness { lazy, nonlazy };
enum logic { AND, OR };
template<laziness LA, logic LO>
struct Node{
template<typename = void>
std::enable_if_t<LA==lazy> printLaziness () const {
std::cout << "lazy" << std::endl;
}
template<typename = void>
std::enable_if_t<LA==nonlazy> printLaziness () const {
std::cout << "non-lazy" << std::endl;
}
};
int main () {
Node<lazy, AND> x{};
x.printLaziness();
Node<nonlazy, OR> y{};
y.printLaziness();
}
代碼格式錯誤,實驗性 gcc 9.0.0 忽略它是錯誤的。
理解 SFINAE 規則的一個關鍵點是,它適用於在將函數模板的參數替換為其他函數模板參數的默認模板參數或函數類型的同時形成無效類型或表達式時,如介紹中所述[temp.deduct]部分; 或者在確定類模板的部分特化是否匹配或哪個部分特化最特化時。 但是在您的代碼中,在替換類模板的參數LA
時形成了無效類型,而不是函數模板的參數。
同樣相關的是[temp.inst]/2 段:
類模板特化的隱式實例化導致
未刪除的類成員函數、成員類、作用域成員枚舉、靜態數據成員、成員模板和朋友的聲明的隱式實例化,但不是定義的隱式實例化; 和
已刪除成員函數、無作用域成員枚舉和成員匿名聯合的定義的隱式實例化。
s of the class member functions.類模板特化的隱式實例化不會導致類成員函數的默認參數或的隱式實例化。
由於main
中x
和y
的定義要求類型Node<lazy, AND>
和Node<nonlazy, OR>
是完整的,因此必須為這兩個特化實例化類模板。 實例化類模板意味着實例化函數模板聲明,因此在每種情況下程序都是格式錯誤的,因為該聲明包含非依賴的無效類型。
旁注:正如您所提到的, if constexpr
可能是在 C++17 中解決此類問題的最簡單方法。 (如果您希望將實現分開,公共函數可以只調用具有不同名稱的兩個私有函數之一。)但是 C++20 將為模板和函數引入“約束”,這將提供更好的解決方案:
template<laziness LA, logic LO>
struct Node{
void printLaziness () const requires (LA==lazy) {
std::cout << "lazy" << std::endl;
}
void printLaziness () const requires (LA==nonlazy) {
std::cout << "non-lazy" << std::endl;
}
};
與 SFINAE 技巧不同,讓成員函數受等價於false
或永遠無法滿足的表達式約束是完全有效的。 這意味着它永遠不會被視為重載決議的可行候選者。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.