使用std::is_base_of实现类SFINAE开关在GCC/Clang编译报错
问题原因
你的SFINAE写法不符合C++标准要求,MSVC属于非标准兼容才允许了你的原有逻辑:
SFINAE机制仅对模板即时上下文中的错误生效,你原有代码中std::is_base_of<QWidget, cls>::value的判定对象cls是外层Wrapper类的模板参数,不属于当前style成员函数模板的即时上下文。当外层Wrapper类用QLayout子类实例化时,编译器会直接检查style函数的函数体,发现setStyleSheet不存在就直接报错,不会触发SFINAE淘汰该函数。
解决方案
方案1:兼容C++11的写法(改动最小)
给成员函数模板新增一个默认值为cls的本地模板参数,让enable_if的判定依赖当前函数模板的参数,即可触发SFINAE:
template<typename T = cls, typename = typename std::enable_if<std::is_base_of<QWidget, T>::value>::type> Wrapper &style(const QString &stylesheet) { cast()->setStyleSheet(stylesheet); return *this; }
该写法和你原有逻辑几乎一致,不需要拆分两套代码,直接替换原有模板声明即可,GCC/Clang均可正常编译。
方案2:C++20及以上简化写法
直接用C++20的requires约束,写法更简洁:
Wrapper &style(const QString &stylesheet) requires std::is_base_of_v<QWidget, cls> { cast()->setStyleSheet(stylesheet); return *this; }
无需额外定义模板参数,编译器会自动在重载决议阶段淘汰不符合约束的函数。
内容的提问来源于stack exchange,提问作者mccatnm
相关产品推荐
相关产品推荐

