对这种语法感到困惑

3

在阅读cppreference.com中有关SFINAE的内容时,我遇到了这个我无法掌握的片段:

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

所以,到底什么是

呢?

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

这看起来像是一个返回字符的函数指针,但方括号中的bool是什么意思?这是一个真实的东西还是只是一些愚蠢的人工示例?


2
下面有一条注释解释了其目的:// 当 I 为偶数时选择此重载 - UnholySheep
我理解了目的。但我不知道指向数组的语法。 - mariachi423
3个回答

4
你看到的是旧式 SFINAE。
背景: SFINAE: Substitution Failure Is Not An Error(替换失败不是错误)。
当你尝试实例化一个模板时,它会检查该模板是否能够无错误地实例化。如果出现错误,则什么也不会发生,当前尝试的模板将被忽略。通常情况下,你有两个或多个模板定义,但一次只能实例化一个没有错误的模板。
在你的情况下,将创建一个数组,如果 I 是偶数,则结果是一个大小为零的数组。这是一个编译错误,但作为模板声明使用时,允许失败并将被忽略。因此,你可以使用这样的语句来选择将根据参数实例化哪个模板。
详细语法:
template <int I> void div(char(*)[I % 2 == 0] = 0)

我们有一个模板,接受一个参数:一个整数I。 然后,该模板定义了一个函数,它接受一个指向char数组的指针,其大小为"I%2==0",这导致从逻辑上将bool转换为int。因此,如果I是偶数,则结果为零-> SFINAE将失败,实例被忽略;如果I是奇数,则结果为true->转换为1。这意味着,您创建了一个大小为1的char指针数组的指针。好的,实例将被创建。在获得指针后,它将被默认初始化为0。
在这里,我们看到偶数或奇数的I可以用于选择将实例化哪个(或多个)模板。
在更“现代”的C ++中,我们看到std :: enable_if用于选择将实例化哪个模板。这使代码更易读。但是,在c ++ 11之前,c ++没有这个功能。因此,经常通过创建负大小或零大小的数组来生成SFINAE的错误。这是旧式代码中常见的hack。

3
也许如果你加入参数名称,这个问题就会变得更加清晰:
void div(char (*x)[I % 2 == 0] = 0)

x是一个指向大小为1(表示为真)或0(表示为假)的数组的指针,默认为nullptr

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


谢谢。对于指向数组的指针语法,我以前并不了解。所以这是一个指向数组的指针:int (*)[],而这是一个指向函数的指针:int(*)() - mariachi423
@griezmanlol 这是正确的。另一方面,int *[] 是一个指针数组,而 int *() 是一个返回指针的函数。 - melpomene
太好了。感谢你的回答。 - mariachi423

2

char(*)[I % 2 == 0] = 0 是指向 char 数组的指针,当 I 为偶数时,数组大小为 1,当 I 为奇数时,数组大小为 0,并且该指针被默认设置为 0。

因为无法创建大小为 0 的数组,所以此重载仅在 I 为偶数时才能调用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接