【问题标题】:What is the advantage of std::enable_if over static_assert for class templates?对于类模板,std::enable_if 比 static_assert 有什么优势?
【发布时间】:2020-12-19 11:11:33
【问题描述】:

我想知道std::enable_if 相对于static_asserts 在防止模板实例化方面的优势。 This answer 建议,std::enable_if 允许 SFINAE,这在 function templates 的情况下是一个令人信服的论点。

但是这个论点对于class templates(和variable templates)是合法的吗?据我所知,那里没有涉及过载解决方案,这使得 SFINAE - 再次,据我所知 - 不相关,但我可能是错的。如果有,你能举个例子吗?

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

【问题讨论】:

  • 如果条件不成立,static_assert 不会阻止实例化。相反,它会使程序格式错误。
  • @Elliott hmmm...
  • @Elliott 标准是这么说的。 "如果转换后表达式的值为真,则声明无效。否则,程序格式错误"

标签: c++ templates enable-if static-assert class-template


【解决方案1】:

如您所说,可以通过专业化来处理一些不同的类型:

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 有助于基于精确的行为而不是精确的类型进行专业化。

【讨论】:

  • “更清晰、更简单”(在没有重载的情况下)并且不会导致类似于在函数重载解析中阻止 SFINAE 的一些缺点,对吗?
  • Nvm,我意识到我之前的评论是以双重标准衡量的。在函数模板 if 中使用static_assert 也没有缺点,我的目标不是重载。所以类和函数模板的类比是相当完整的。
  • @Reizo,是的,我对你的问题有点困惑。如果您使用static_assert 而不是enable_if,那么它将阻止您进行重载(仅基于该模板[您仍然可以基于其他参数/​​模板重载])
【解决方案2】:

但是这个参数对于类模板(和变量模板)是合法的吗?据我所知,那里没有涉及过载解决方案,这使得 SFINAE - 再次,据我所知 - 不相关,但我可能是错的。如果有,你能举个例子吗?

您可以专业化类模板,SFINAE 可用于在专业化之间进行选择。它还将阻止此类(到那时,可能是格式错误的)类/其专业化的实例化,而不是由于static_assert而无法编译。

【讨论】:

  • 我不知道模板类型规范是如何模棱两可的,需要“在 [可能的] 特化之间进行选择”。你能在你的答案中添加一个例子吗?
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 2017-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-04
    相关资源
    最近更新 更多