【问题标题】:What is the reason for providing a default value of zero for SFINAE testers?为 SFINAE 测试人员提供默认值零的原因是什么?
【发布时间】:2014-12-14 03:10:30
【问题描述】:

我注意到许多 boost 和 libc++/libstdc++ 在类似代码中为 SFINAE 明确提供了一个默认值为零

// libc++ http://llvm.org/svn/llvm-project/libcxx/trunk/include/memory
namespace __has_pointer_type_imp
{
    template <class _Up> static __two __test(...);
    template <class _Up> static char __test(typename _Up::pointer* = 0);
}

template <class _Tp>
struct __has_pointer_type
    : public integral_constant<bool, sizeof(__has_pointer_type_imp::__test<_Tp>(0)) == 1>
{
};

但是,这让我感到困惑,为什么当他们明确地使用 0 进行调用时会出现这种情况。我记得在某处听到这是一种优化(在实例化模板时加速编译器),但我不完全理解如何那行得通。我查看了标准,其中有一个部分简要描述了与模板参数推导相关的默认参数会发生什么。

14.8.2

在模板实参推导过程中的某些点,有必要采用一个使用模板形参的函数类型,并将这些模板形参替换为相应的模板实参。当任何显式指定的模板参数被替换到函数类型中时,这在模板参数推导的开头完成,并且当从默认参数推导或获得的任何模板参数被替换时,在模板参数推导结束时再次完成。

最后一点听起来与我的问题有关

当替换任何从默认参数推导或获得的模板参数时,在模板参数推导结束时再次。

但是,如果必须做更多工作,这听起来与优化相反。有没有人有任何理由为什么 0 必须在那里,没有它它也可以工作,但是 libc++ 中的每个 SFINAE 示例至少似乎都明确地将 0 放在那里,即使他们从未在没有参数的情况下调用该函数。

【问题讨论】:

  • 我不知道确切的原因,但可能会在调用表达式中没有传入0而不是假阴性时引发“模糊调用错误”(如@987654323 @version 匹配空参数,而非默认的不匹配)
  • 不是和空指针分析有关吗?就像默认的零可能会禁用空指针的静态分析,这反过来又避免了在运行 clang 静态分析器时出现大量误报。出于同样的原因,也可能会略微加快编译速度。只是猜测......你应该在 llvm 邮件列表上询问(然后回到这里来启发我们;))
  • 有各种各样的解释 - 如果没有阅读该库的设计/实现文档或(失败)询问开发人员,这是不可能知道的。它可以是这个库的开发人员遵循的样式指南中的指南一样简单的东西。

标签: c++ templates c++11 sfinae libc++


【解决方案1】:

您提供默认值是因为您希望能够不提供该参数,尽管条件仍处于检查状态!

例子:

template<typename T,
        typename std::enable_if<
                std::is_floating_point_v<T>
                               >::type = 0>
void foo() { std::cout << "1"; }

然后可以在 main 中调用这个函数,只需要一个模板参数!更好的是,甚至不需要命名第二个参数,因为它没有被使用。

在函数foo的输入中给出参数时的类似例子:

template<class T>
void foo(T t,
         typename std::enable_if<
                       std::is_floating_point_v<T>
                  >::type = 0) { std::cout << "2"; }

那么你可以给函数foo提供第二个参数,但你通常不想这样做。

【讨论】:

  • std::enable_if&lt;std::is_floating_point_v&lt;T&gt;&gt;::type = 0 不起作用,因为type 默认为void,因此不能为0。问题是关于默认 function 参数,而不是默认 template 参数。
  • @alterigel,你的意思是代码不能编译吗?因为对我来说确实如此。我不明白您所说的默认函数/模板参数是什么意思。我在 OP 中清楚地看到了与我的回答中描述的相同的模式。你能提供更多细节吗?
  • @MarineGalantin 是的,但这不是 OP 的问题。实际上是相反的:当函数总是在非 SFINAE 上下文中显式使用时,为什么它们提供默认参数,或者更准确地说:为什么它们为对该方法的所有调用提供显式零?
  • @Secundi 0 不是强制性的,正如 OP 所指出的那样。代码在没有它的情况下编译。但是,正如我在回答中所解释的那样,SFINAE 的全部意义在于拥有一个0,这使整个概念发挥作用。我不明白你的评论,问题是为什么会有0(据我了解)。
  • '然而,SFINAE 的重点是 0,这使得整个概念起作用'我知道它是如何工作的,但我怀疑这与这个特定问题是否真的有一些相关性,因为此处必须始终提供零。 Piotr Skotnicki 是对的,这是由于在意外忘记提供显式零时,干净地防止了假阴性(甚至更大的混乱,取决于可变参数的实际实现)。然而,独立于可变参数的实际实现,它遵循早期错误原则。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-07
  • 1970-01-01
  • 2018-11-10
  • 1970-01-01
  • 2010-10-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多