函数参数列表周围的双括号

3

我有以下代码,使用gcc 4.4编译时没有警告,并返回42。

template<typename T>
struct foo
{ };

template<typename T>
struct foo<void (T)>
{
  enum { value = 42 };
};

int main()
{
  return foo<void ((int))>::value;
}

现在我明白了,当模板参数为时为何会起作用,但双括号是怎么回事呢?这在C++中是否合法?它和一样吗?
谢谢。

我显然漏掉了什么... honk 和另一个用户觉得有必要指出 C++ 不是 Python - 但为什么呢?这段代码对我来说似乎完全不像 Python。 - user395760
@delnan 在 Python 中,额外的括号具有特定的含义,但在 C++ 中它们则没有。当一个笑话需要被解释时,它就不再有趣了。 - Mark Ransom
@Mark:如果一个笑话基于错误信息,那么它也不好笑。你们难道不会Python吗?现在,(expr,)将是一个单元素元组,但(expr)只是expr。在Python中,简单地用括号包装某些东西并不会改变它的任何内容,就像在任何明智的语言中一样。 - user395760
@Mark, @delnan,你们是对的,我现在脑子有点晕乎 - Benjamin Bannier
如果第二个结构体foo是一个特化版本,那么模板行不应该是template <>吗? - Adrian McCarthy
@Adrian:这是函数类型的部分特化,仍然由函数的参数类型参数化。 - Mike Seymour
4个回答

4
在这种情况下,void ((int))void (int) 相同。
foo<void ((int))> 中的 void ((int)) 部分被称为 type-id
根据 §8.1/1,type-idtype-specifier-seqabstract-declarator 组成。
void ((int)) 中,type-specifier-seqvoidabstract-declarator((int)),并且 abstract-declarator 可以任意加括号。
这在 C 和 C++ 中都是合法的。

2
这是答案。void ((int)) 是一个有趣的类型标识符,意味着在有趣的声明 void (g(int)) 中声明了类型 g,其含义与更常见的声明 void g(int) 相同。 - aschepler

3
内部括号用于改变表达式的评估顺序。当表达式只有一个部分时,顺序并不重要,因此它们实际上没有起到任何作用。

1
如果这是合法的,为什么g++会拒绝void f((int)) {}?我怀疑原始示例是无效的语法,并且它被接受是编译器错误。 - aschepler
这是正确的,但它适用于这里吗?在表达式中冗余的括号并不重要,但这是一种类型规范。 - Adrian McCarthy
@Adrian,类型表达式也是一种表达式。在这种情况下,括号并不重要,但有很多例子说明它们确实很重要。 - Mark Ransom
@aschepler,我认为你的例子是我上面提到的情况之一。通过告诉编译器从int开始表达式评估,它不再像函数规范那样。 - Mark Ransom
1
好的,但是在这里没有涉及到任何表达式或评估。 - aschepler

1
  • 模板与宏定义不同。

  • 你的 "void (T)" 与 "void T" 相同,"void ((int))" 与 "void int" 相同,就像 "void ((((int))))" 与 "void int" 相同。括号中的表达式会被计算,正如 @Mark 指出的那样。


1
没有涉及到任何表达式,也没有进行任何计算。 - aschepler

0
在这种情况下,这并不是必要的,但是像这样使用双括号的主要原因是为了避免最令人烦恼的解析。
双括号在函数声明中不被允许,但在函数调用中是可以的,因此,通过将至少一个参数括在双括号中,可以强制将本来会产生最令人烦恼的解析的代码变成函数调用。
我在先前的答案中包含的一些代码就展示了这一点。

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