SFINAE: Understanding void_t and detect_if
SFINAE: Understanding void_t and detect_if
我正在学习模板元编程,最近,我在CPPConference上看到了一个关于void_t的演讲。不久之后,我发现了检测成语。
但是,我仍然很难理解其中任何一个(尤其是检测习语,因为它基于 void_t(。我读了这篇博文,还有这篇 stackoverflow 文章,它对我有所帮助,但我仍然有一些问题。
如果我的理解是正确的,如果 void_t 中的表达式无效,它将使用以下表达式进行 SFINAE:
template< class, class = std::void_t<> >
struct has_type_member : std::false_type { };
因为 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_t?
好吧,我并不是说我自己完全理解了所有内容,但我会尽我所能回答:
因为 class 在这里是一个默认模板参数,可以表示独立于其类型的任意数量的参数?
近。此模板将使用一个或两个模板参数匹配任何实例化,因此所有表单都has_type_member<T>
或has_type_member<T, U>
。这是由于
class
匹配任何类型。但这并不特别(你也可以写class T
你只是不需要这个名字,因为你没有在声明中引用它(每个模板一开始都匹配所有类型,只能通过参数的数量来区分。通常,我们要么通过一些SFINAE-magic(如enable_if
(进行约束,要么稍后通过部分模板规范更好地拟合。class = void
匹配每种类型,如上所述,也根本没有类型,因为如果我们没有参数,void
填充。
我们只会将此模板实例化为has_member_type<T>
,因此这始终是第一个匹配项,但可能不是最佳匹配项。但是作为第一个匹配,它告诉我们:第二个模板参数必须是void
的,因为所有进一步的匹配必须是部分规范。否则我们会模棱两可。想想看,如果第二个模板能给我们int
表达式是否有效,会发生什么。然后我们has_type_member<T, void>
和has_type_member<T, int>
两场比赛,那么我们应该选择哪一场比赛呢?这就是为什么在成功的情况下必须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<...>
无法对它进行修饰,因此部分规范是无效的,所以我们不能选择它,但这没问题,因为替换失败不是错误,所以我们只是继续我们已经找到的,主模板。
甚至有必要说类等于std::void_t<>吗?写还不够吗
template< class, class = void > struct has_type_member : std::false_type { };
如果没有,为什么?
是的,它会,它也在谈话中完成。void_t<>
实际上是void
.我认为void_t
只是为了与第二个规范更一致。需要void_t
,因为我们需要这个模板。
- C++核心准则 C35 对于接口类"A base class destructor should be either public and virtual, or protected and nonv
- 为什么C++逐位AND运算符在不同大小的操作数中表现为这样
- 为什么 Clang 不允许"and"作为函数名称?
- 位阵列上的快速AND运算
- 是否可以在 C++03 中定义'move-and-swap idiom'等效项
- BoostPython and CMake
- OpenSSL BIO and SSL_read
- Gurobi GRBModel and GRBmodel in C++
- std::visit and std::variant usage
- SHBrowseForFolder with BIF_BROWSEFORCOMPUTER and SHGetPathFr
- Directx12 and keystrokes
- different between int **arr =new int [ n]; and int a[i][j]?
- C++ getenv and setenv
- Inference pytorch C++ with alexnet and cv::imread image
- Visual Studio 2019 C++ and std::filesystem
- 保证逻辑 AND 表达式中的函数调用
- python ctypes and C++ pointers
- C++ const char with .begin() and .end()
- Threads with Classes and std::packaged_task
- Detect Windows Kit 8.0 and Windows Kit 8.1 SDKs