被这种语法弄糊涂了

Puzzled by this syntax

本文关键字:弄糊涂 语法      更新时间:2023-10-16

当我在cppreference.com上阅读关于SFINAE的文章时,我遇到了一个我无法理解的片段:

template <int I> void div(char(*)[I % 2 == 0] = 0) 

到底是什么

char(*)[I % 2 == 0] = 0

它看起来像是一个指向返回char的函数的指针,但带bool的方括号是什么?它是真的吗?还是只是一些愚蠢的人造例子?

您看到的是旧时尚风格的SFINAE。

背景:SFINAE:替换失败不是错误

当您尝试实例化一个模板时,它会检查该模板是否可以在没有错误的情况下实例化。如果发生错误,则根本不会发生任何事情,当前尝试的模板将被忽略。通常,您有两个或多个模板定义,但一次只能实例化一个模板定义而不会出现错误。

在您的情况下,将创建一个数组,如果我是偶数,则结果是大小为零的数组。这是一个编译错误,但用作模板声明时,它会失败并被忽略。因此,您可以使用这样的语句来选择将根据参数实例化哪个模板。

详细语法:

template <int I> void div(char(*)[I % 2 == 0] = 0)

我们有一个模板,采用一个参数:int I。然后,模板定义了一个函数,该函数将指针指向一个大小为"I%2==0"的char数组,这将导致逻辑从bool到int的转换。因此,如果我是偶数,则结果为零->SFINAE将失败,实例被忽略,如果我为奇数,则得到true->转换为1。这意味着,创建一个指向大小为1的字符指针数组的指针。好的,将创建实例。在有了指针之后,它将默认初始化为0。

在这里,我们看到偶数或奇数I可以用来选择两个(或多个(模板中的哪一个将被实例化。

在更"现代"的C++中,我们看到std::enable_if来选择要实例化的模板。这使其可读性更强。但是在c++11之前,c++没有这个。因此,为SFINAE生成错误的需要通常是通过创建负或零大小的数组来完成的。这是老式代码中常见的SFINAE破解方法。

如果将参数名称放入:中,可能会变得更清楚

void div(char (*x)[I % 2 == 0] = 0)

x是指向大小为1(表示true(或0(表示false(的数组的指针,默认为nullptr

但是参数名称在C++中是可选的,所以如果函数不使用x,它可以省略名称。

char(*)[I % 2 == 0] = 0是大小为1的字符数组上的指针(当I为偶数时(和0(当我为奇数时(,指针默认为0

因为您不能创建大小等于0的数组,所以只有当我是时才能调用此重载