【发布时间】:2016-10-01 10:11:36
【问题描述】:
这看起来像是 clang 中的一个问题(我已经打开了一个错误 here),但我想确定我没有做错。
考虑以下代码:
#include <type_traits>
#include <cstddef>
template<std::size_t N, std::size_t M, std::enable_if_t<not (N>M)>* = nullptr> // (1)
struct S: public S<N+1, M> { };
template<std::size_t N>
struct S<N, N> { };
int main() {
S<0, 1> c{};
}
编译失败,报如下错误:
8 : 错误:非类型模板参数专门化了具有依赖类型'std::enable_if_t M)> *' (aka 'typename enable_if M), void>::type *')的模板参数
结构 S { };
使用以下行而不是 (1),相同的代码按预期工作:
template<std::size_t N, std::size_t M, typename = std::enable_if_t<not (N>M)>>
SFINAE 表达式几乎相同。它基于 std::enable_if_t 的专业化,我希望这两个示例的结果相同(成功或失败)。
我的期望错了吗?
请注意,GCC 在任何一种情况下都可以正常工作。
【问题讨论】:
-
整件事对我来说似乎不起作用。主模板中的参数类型总是会被构造,无论是选择它还是选择特化。所以 enable_if 总是会失败,
main方法的格式会不正确。 -
相关文本是“在引用类模板特化的类型名称中,(例如,A
)参数列表应与主模板的模板参数列表匹配. 特化的模板参数是从主模板的参数推导出来的。”。 “主模板的参数”是隐含的参数列表,它在概念上遵循非特殊情况: struct S<N,M,<unnamed>>。在您的情况下,未命名参数的类型无效,这将导致代码格式错误。 -
@JohannesSchaub-litb 整个事情与 GCC 一样工作(即使它不应该,但 sfinae 表达式是有效的)。如果您在
typename = std::enable_if<...中更改它,它仍然有效,这次是使用 GCC 和 clang。例如,S<0, 2>被接受,而S<2, 0>不被接受。enable_if在第一种情况下不会失败,但在第二种情况下会失败。我不明白你的意思,对不起。 -
我的意思是您的参数类型不是 SFINAE 上下文。您可能已经在偏特化中看到
enable_if表达式,它们位于 SFINAE 上下文中,但作为主模板中的类型,它们不是 SFINAE 上下文。并且将它作为默认参数可能会做一些你认为它做的事情:你可能期望它编译:coliru.stacked-crooked.com/a/486ba2517bf67c18 -
我的意思是它不是一个 sfinae 表达式。这只是一个“替换失败是错误”的表达。如果
S<N,M>中的 N>M,则您的代码总是格式错误的。那里没有 SFINAE 的“不是错误”部分。术语 SFINAE 用于替换失败但它不是错误并且可以考虑替代声明的情况(在我的示例中为S<2, 1>)。
标签: gcc clang c++14 sfinae enable-if