【发布时间】:2022-01-04 02:45:16
【问题描述】:
我正在开发用于声明式 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 子类没有成员 setStyleSheet。虽然没有,但我希望编译器能像在 MSVC 中那样完全跳过该函数。
我假设我对 SFINAE 系统有误解,需要调整我的模板声明,或者干脆把它收起来,拆分两个项目并重复代码。
编辑:
问题的再现: https://gcc.godbolt.org/z/oGzsKhrn4
上面的位只是 Qt 对象的最小代表,它代表了我所追求的相同基本结构,你几乎可以忽略它们。
宏是为了简化每个类所需的模板。如果不出意外,我总是可以将它分解并添加额外的宏来填充 QWidget 与 QLayout 功能,我只是喜欢它在 Windows 上的干净程度。
【问题讨论】:
-
什么是
cls?和style()有什么关系? -
直到最近,MSVC 还没有正确实现两阶段名称查找。本质上,它将模板视为宏并对其进行解析以找到右大括号;然后在实例化时完全重新解析它们。这是不合格的;符合标准的编译器将在定义点解析和验证大部分模板,并且仅在实例化点推迟查找依赖名称。您可能依赖于 MSVC 的这一缺陷。如需进一步帮助,请准备minimal reproducible example。正如所写,尚不清楚
cls、cast()或stylesheet是什么。 -
Minimal 对我来说是一个挑战,因为我其他小规模复制的大多数尝试都失败了。我确实设法整理了一些确实会引发错误并更新了问题的东西,但它并不是很小。
-
呃,宏滥用。您能否尝试提出一个不使用使代码难以理解和理解的宏的minimal reproducible example?
-
公平点 - 我已经解压缩了宏并尝试尽可能减少,同时仍然包括我所追求的全貌。也就是说,我最终只是将宏拆分以避免问题。这是每个包装类的额外代码行,但比再继续旋转要好