这个 SFINAE C++语法是如何工作的
How does this SFINAE C++ syntax work?
我刚刚开始涉足SFINAE,我很难理解以各种形式出现的最常用示例背后的语法,但这个想法是检查特定类型是否包含给定的成员。这个特别的来自维基百科:
template <typename T> struct has_typedef_foobar
{
typedef char yes[1];
typedef char no[2];
template <typename C> static yes& test(typename C::foobar*);
template <typename> static no& test(...);
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
有几件事我不明白:
- 返回"yes"的 test() 重载的参数类型是什么?是指针吗?为什么将 typename 关键字用作参数的一部分?我已经看到它也用于测试一个类是否具有给定类型的成员,而不仅仅是 typedef,并且语法保持不变。
- 有时我看到使用test(int C::*)的例子。这更奇怪,不知道我们指的是C的哪个成员。如果它是一个带有主体的实函数,为实数类型实例化,并且参数被命名,它会指向什么以及如何使用它?
模板
这些问题中的大多数与SFINAE无关:
- 当依赖名称应被视为类型时,它前面需要加上
typename
。由于C
是要test()
的模板参数,显然C::foobar
是一个依赖名称。尽管函数声明要求在每个参数前面都有一个类型,但该语言需要使用typename
将依赖名称C::foobar
转换为类型。这样,typename C::foobar
只是一个类型,*
应用类型构造函数,就会生成相应的指针类型。 -
int C::*
是指向类型为int
的数据成员的未命名指针。 - 未使用的名称始终可以省略。这适用于函数参数以及模板参数,即,是的,如果不使用它,则可以省略
template
后面的名称。但是,大多数时候它以某种形式使用,在这种情况下,显然是必需的。 - 我认为你可以写一个测试来测试多个方面的存在,但我不会这样做:SFINAE 是不可读的。我宁愿显式地将不同的属性测试与普通逻辑运算符相结合。
- 当依赖名称应被视为类型时,它前面需要加上
SFINAE 的这个示例依赖于这样一个事实,即参数列表为 ...
的函数在执行重载解析时是最不首选的。
所以首先,编译器将尝试
static yes& test(typename C::foobar*);
通过用C
替换实际类型。如果C
有一个名为 foobar
的成员类型,它将编译并选择。否则,它将编译失败,并且将选择...
重载。它将始终编译。因此,要回答您的第一个问题,返回 yes&
的类型是具有成员类型的任何内容 foobar
.
单词 typename
对于依赖类型是必需的:依赖于模板参数的类型。由于这些类型可以是变量名或类型名,因此编译器假定它是变量名,除非您使用 typename
告诉它。从理论上讲,它可以自行检查,但这会使编译器编写起来更加复杂,这显然是不可取的。
至于你的第二个问题,这是一个成员变量指针。您还可以使用成员函数指针,其完整形式实际上类似于 void test(int(C::*arg_name)())
。
至于三个,是的,它是允许的,但从不使用模板参数。由于您没有使用推导,而是显式指定参数,因此可以。就像像void f(int);
这样的未命名的正常参数一样.
至于四个,是的,它可以,但就我所知的方式,你只需要为 n 个要测试的成员提供 n * 2 个函数。对于两个人来说,它看起来像
template <typename C> static yes& test1(typename C::foobar*);
template <typename> static no& test1(...);
template <typename C> static yes& test2(typename C::quux*);
template <typename> static no& test2(...);
static const bool value = sizeof(test1<T>(0)) + sizeof(test2<T>(0)) == sizeof(yes) * 2;
类型的模板中需要typename
,在这种情况下C::foobar
是参数C
的依赖类型。test() 的参数类型是指向 C::foobar 的指针。如果 C::foobar 不是类型,则该版本的测试重载将无法编译,并且将找到另一个版本的重载。
UK4321涵盖了其余部分。
- QSqlquery prepare()和bindvalue()不工作
- 导入库可以跨dll版本工作吗
- 以螺旋方式打印矩阵的程序.(工作不好)
- 对象指针在c++中是如何工作的
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- C++为线程工作动态地分割例程
- 为什么我的 std::ref 无法按预期工作?
- 布尔比较运算符是如何在C++中工作的
- SampleConsensusPrerejective(ext.RANSAC)是如何真正工作的
- 不确定要在我的main中放入什么才能使我的代码正常工作
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- <<操作员在下面的行中工作
- 有人能解释一下为什么下界是这样工作的吗C++的
- ExtractIconEx:可以工作,但偶尔会崩溃
- C++中的memset函数工作不正常
- 当我在第一个循环中使用"auto"时,它工作正常,但是使用"int"它会给出错误,为什么?
- 当 int 方法工作正常时,void 方法有何不同,或者为什么我不能调用 void 方法?
- sdl软件渲染器不工作,工作在硬件加速的一个