【问题标题】:SFINAE: static_assert vs std::enable_ifSFINAE:static_assert 与 std::enable_if
【发布时间】:2013-06-03 07:56:25
【问题描述】:

以下(建议!)语法有什么缺点吗?

template< typename T >
void f() static_assert(std::is_same< T, int >::value)
{ ; }

而不是 SFINAE(看起来像拐杖):

template< typename T, typename = typename std::enable_if< std::is_same< T, int >::value >::type >
void f() { ; }

甚至更糟:

template< typename T >
typename std::enable_if< std::is_same< T, int >::value >::type 
f() 
{ ; }

其中禁止使用auto推导结果类型。

【问题讨论】:

  • static_assert 不是 SFINAE,它是对必须为真的事物的断言。
  • 那不是一个有效的 c++11 代码
  • @BЈовић 我知道。这只是一种可能的语法建议。
  • 同时,有可能是more concise
  • @Piotr99,废话,如果新提案在以前无法使用的上下文中使用关键字,这不是问题,因为这不会与现有代码的含义发生冲突或改变.例如,在 C++ 的类成员上使用 C 关键字 static,或者在 C++11 中使用 extern 进行显式实例化声明,或者在 C++11 中使用 using 作为类型别名,或者使用 auto 作为在 C++11 中的类型推导,或在 C++11 中使用 inline 用于命名空间,或在 C++11 中的 lambda 表达式中使用 mutable,或在 C++14 中使用 auto 用于通用 lambda 等.等等

标签: c++ sfinae c++14


【解决方案1】:

首先,它们是不同的,特别是它们不是同时检查的。

关键的区别在于它们在重载解析方面的应用。 SFINAE 将从重载集中剔除函数,以便选择另一个函数(如果有),而 static_assert 在重载决议之后应用,因此将给出一个 错误停止编译。

现在,关于您的投诉,您可以完美地使用auto 和 SFINAE:

// Ensure that T is int
template <typename T>
auto f() -> typename std::enable_if< std::is_same< T, int >::value >::type
{ ... }

// Only pick this overload if begin(c) and end(c) are available
template <typename T>
auto f(T const& c) -> decltype(begin(c), end(c), bool{}) { ... }

...你可以完美使用SFINAE和自动类型推断

template <typename T,
          typename = typename std::enable_if<std::is_same<T, int>::value>::type>
auto f() { ... }

template <typename T>
auto f(void* =
       typename std::enable_if<std::is_same<T, int>::value>::type*(0))
{ ... }

【讨论】:

  • 但我的问题只是关于目前形式的 SFINAE 语句的冗长(以及如何处理)。
  • @Dukales:啊,是的,确实很冗长。您可能会为经常使用的测试使用模板别名:template &lt;typename L, typename R&gt; using enable_if_same = std::enable_if&lt;std::is_same&lt;L, R&gt;::value&gt;::type;,然后是 template &lt;typename T, typename = enable_if_same&lt;T, int&gt;&gt; auto f() { ... } ... 另请注意,对于 C++1y,返回类型的实际推导(如 lambdas)是在盘子上的。
  • 我对新的 C++ 标准的特性特别感兴趣。无论如何,我主要使用一次的每个 SFINAE 条件。因此别名不是通用的解决方案。
  • @MatthieuM。您确定 static_assert 不涉及重载解析吗?在少数情况下,添加 static_assert 会使代码调用函数的不同重载版本。也许它在那里工作是因为重载是一个非模板函数?
  • @peterkarasev:我敢肯定,重载解决方案仅基于签名,而 static_assert 出现在实现中。同样,SFINAE 仅基于直接上下文(因此是签名/声明)。
【解决方案2】:

为什么使用static_assertConcepts Lite 语法更好?

template< typename T >
  void f() requires Int<T>()
  { }

或:

template< Int T >
  void f()
  { }

【讨论】:

  • static_assert 只是一个提议。我之前不知道 (proposal) requires 关键字的存在。它看起来像解决方案。
  • @0x499602D2,是的,有一个 GCC 的分支可以实现它,请参阅 concepts.axiomatics.org/~ans。您需要定义 Int 约束,例如template&lt;typename T&gt; constexpr bool Int() { return std::is_same&lt; T, int &gt;::value; }
  • 如果我错了,请原谅我,但直到现在 C++20 还没有概念被搁置?
  • @Pharap 是的,但这不会改变上述答案中的任何内容,只是您不再需要使用 GCC 的分支。 GCC 7 支持由-fconcepts 命令行选项启用的概念。
  • @JonathanWakely 如果在引入“C++17 概念”之前,有人只是打算使用精简版概念,这可能会改变一些事情。依赖于特定于编译器的扩展需要额外的 3 年时间。
猜你喜欢
  • 2012-10-26
  • 2012-06-18
  • 2014-08-29
  • 2016-02-25
  • 2021-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-30
相关资源
最近更新 更多