对于 class 模板,std::enable_if 相对于 static_assert 的优势是什么?

What is the advantage of std::enable_if over static_assert for class templates?

我想知道 std::enable_if over static_asserts to prevent template instantiation. This answer suggests, that std::enable_if allows SFINAE, which is a convincing argument in the case of function templates 的优势。

然而,这个论点对 class templates (and variable templates) 来说是否合理?据我所知,那里没有涉及重载决议,这使得 SFINAE - 再次,据我所知 - 不相关,但我可能是错的。如果是这样,你能举个例子吗?

如果不是,我假设 static_assert 是针对 class 模板的给定问题(防止模板实例化)的更好解决方案,因为它可以说更明确、简洁和可读允许自定义错误消息。这是正确的还是我遗漏了 SFINAE 以外的一点?

However is this argument legitimate for class templates (and variable templates)? As far as I know, there is no overload resolution involved there, making SFINAE - again, as far as I know - not relevant, but I might be wrong. If so, can you name an example?

您可以专业化 class 模板,SFINAE 可用于在专业化之间进行选择。它还将阻止此类实例化(到那时,可能 ill-formed)class/它的特化,而不是由于 static_assert.

而无法编译

处理几个不同的类型可以像你说的那样通过专门化来完成:

template <class>
class foo;

template <>
class foo <int> { /* int implementation */ };

template <>
class foo <char> { /* char implementation */ };

现在考虑我们想要特化多个类型,并且我们希望 floatdouble 处于相同的特化中。如果没有 SFINAE,我们无法做到这一点,因此为了避免重复实现,我们使用继承:

class foo_fp_implementation {
    /* specialise for all floating point */ 
};

template <>
class foo <float> : foo_fp_implementation {};

template <>
class foo <double> : foo_fp_implementation {};

到目前为止,我们已经避免了 SFINAE,但是如果您想要一个接受具有特定接口的所有类型的专业化怎么办?示例:有方法 int bar ()?我们可以尝试使用上面的技巧并列出所有可能的类型,但是如果要维护的类型太多,或者您希望其他可能使用自己的类型的人可以使用它怎么办。这里 SFINAE 来拯救:

template <class, class = int>
class foo;

template <class T>
class foo <T, decltype(T().bar())> {
    // implement using bar interface
};

// other specialisations...

遇到上述情况,static_assert根本无能为力


总而言之,SFINAE 有助于根据精确的 行为 而不是精确的 类型 .

进行专业化

std::enabled_if 在 SFIANE 中用于模板 类、方法和 .... static_assert 用于在编译时检查合约,并提供有用的错误消息。