繁体   English   中英

SFINAE:了解 void_t 和 detect_if

[英]SFINAE: Understanding void_t and detect_if

我正在学习模板元编程,最近,我在CPPConference上看到了一个关于 void_t 的演讲。 不久之后,我发现了检测成语

但是,我仍然很难理解其中任何一个(尤其是检测习惯用法,因为它基于 void_t)。 我阅读了这篇博文和这篇stackoverflow 文章,这对我有所帮助,但我仍然有一些问题。

如果我的理解是正确的,如果 void_t 中的表达式无效,它将使用以下表达式进行 SFINAEd 输出:

template< class, class = std::void_t<> >
struct has_type_member : std::false_type { };

因为 class 在这里是一个默认的模板参数,它可以表示任意数量的独立于其类型的参数? 甚至有必要说 class 等于 std::void_t<> 吗? 写出来还不够

template< class, class = void >
struct has_type_member : std::false_type { };

如果不是,为什么?

但是,如果表达式有效,则此表达式将被称为计算结果为 void:

template< class T >
struct has_type_member<T, std::void_t<typename T::type>> : std::true_type { };

为什么一个有效的表达式会被评估为 void,这对我们有什么帮助? 另外,为什么表达式需要有效才能匹配 void_t?

好吧,我并没有声称我自己完全理解所有内容,但我会尽我所知尽力回答:

因为 class 在这里是一个默认的模板参数,它可以表示任意数量的独立于其类型的参数?

几乎。 此模板将匹配具有一两个模板参数的任何实例化,因此所有形式都为has_type_member<T>has_type_member<T, U> 这是因为

  • class匹配任何类型。 但这并不特别(您也可以编写class T您只是不需要名称,因为您没有在声明中引用它)每个模板最初都匹配所有类型,并且只能通过参数数量来区分。 通常情况下,我们要么通过一些 SFINAE 魔术(如enable_if )进行约束,要么稍后通过部分模板规范更好地适应。
  • class = void匹配所有类型,如上所述,也根本没有类型,因为如果我们没有参数,则void填充。

我们只会将此模板实例化为has_member_type<T> ,因此这将始终是第一个匹配项,但可能不是最佳匹配项。 但是作为第一个匹配项,它告诉我们:第二个模板参数必须是void ,因为所有进一步的匹配项必须是部分规范。 否则我们就会产生歧义。 想一想,如果表达式有效,第二个模板会给我们int会发生什么。 然后我们有两个匹配has_type_member<T, void>has_type_member<T, int> ,那么我们应该选择哪个? 这就是为什么在成功的情况下,类型必须是void然后也选择这个重载,因为它更特殊。

为什么一个有效的表达式会被评估为 void,这对我们有什么帮助? 另外,为什么表达式需要有效才能匹配 void_t?

所以第一个问题的第二部分我已经回答了。 关于第一个:想想void_t的定义:

template<class...>
using void_t = void;

那么, ...匹配所有类型和数量的所有内容,不是吗? 实际上它只匹配一个有效的类型,如果不匹配它怎么可能使用这种类型? (我知道它不使用该类型,但它必须能够使用。并且它不能使用无效类型)。 因此,如果传递的模板参数有效,它会给我们void 所以在我们的用例中:

如果T具有成员类型T::type ,则T::type是有效类型并且void_t<...>匹配它。 所以我们在这一点上得到void_t<T::type> ,它的计算结果为void ,它适合主要但更特殊,所以我们取它并得到一个true_type

如果我们没有类型成员怎么办? 那么表达式T::type是无效的, void_t<...>不能对其进行 mazch,因此部分规范无效,所以我们不能选择它,但这没问题,因为替换失败不是错误,所以我们就去继续我们已经找到的主模板。

甚至有必要说 class 等于 std::void_t<> 吗? 写出来还不够

template< class, class = void > struct has_type_member : std::false_type { };

如果不是,为什么?

是的,它会,它也在谈话中完成。 void_t<>字面上是void 我认为void_t只是为了与第二个规范更一致。 需要void_t ,因为我们需要这个 template.l

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM