学究队长救援!
如果你写
int(value)
这就是所谓的显式类型转换,由 §5.2.3 管理。确切的措辞是这样的
一个简单类型说明符(7.1.5)后跟一个带括号的表达式列表构造一个给定表达式列表的指定类型的值。 如果表达式列表是单个表达式,则类型转换表达式等效于(在定义上,如果在含义上定义)对应的强制转换表达式 (5.4)
(我的重点)。所以这意味着
int(value)
和
(int)value
彼此完全相同。由您选择您认为更容易编写的任何一个。
关于你的第二个问题,在你给出的模板和数组的例子中,我相信你的意思是这样写的。
template <typename T, size_t N>
size_t (T (&)[N]) {
return N;
}
这里,N 和 T 是一个模板参数,它允许您传入任何您想要的数组,同时让编译器用数组中的元素数填充 N。如果这看起来令人困惑(T (&)[N] 到底是什么?),那是因为这个函数接受了 T (&)[N] 类型的参数。为了便于阅读,我们给这个参数起个名字,如下所示:
template <typename T, size_t N>
size_t (T (&array)[N]) {
return N;
}
我认为这使阅读更容易一些。但是这个声明是什么意思呢?
T (&array)[N]
这声明了一个名为 array 的变量,它是对 Ts 的数组的引用,该数组恰好是 N 元素。您确实可以声明对数组的引用,就像您可以声明指向数组的指针一样。这在实践中并不常见,但在这个特定的模板习语中,它是让编译器在尝试将数组与模板参数匹配时为您推断数组大小的好方法。
在这种情况下括号的原因是如果你写
T& array[N]
编译器会将其解析为“一个名为 array 的变量,它是 N 对象的数组,每个对象都是 T&。但是,C++ 规范明确禁止引用数组,这是非法的.括号明确地消除了歧义。这类似于函数指针-您编写
void (*functionPointer)()
而不是
void *functionPointer()
让编译器意识到* 意味着functionPointer 是一个指针,而不是一个返回void * 的函数。
至于编译器如何确定何时以各种方式处理括号,规则相当复杂,实际上在某些情况下编译器不会以预期的方式解析您的表达式。其中一种情况是通俗地称为“最令人烦恼的解析”,其中编译器将看起来像对象构造的东西视为函数原型。例如,这段代码:
vector<int> v();
不会创建一个名为v 的vector<int>,并使用默认构造函数进行初始化。相反,它将它视为一个名为v 的函数的函数原型,该函数不接受任何参数并生成一个vector<int>!但是,如果你要写
vector<int> v(10);
然后编译器可以明确推断这是 vector<int> 的声明,将 10 作为构造函数参数传递,因为它不可能被视为函数原型。规范的 §6.8 和 §8.2 处理这些情况时说,任何可以被视为声明的东西都将是,任何可以被视为函数原型的东西也将是。
数组上下文中的括号大小写(即T (&array)[N])由不同的逻辑处理,因为在上下文中您要声明变量或定义类型需要显式括号的参数,你的意图不会有歧义,因为从上下文中可以清楚地看出,你命名一个类型是为了声明一个变量。
总结一下-
-
T(value) 和 (T)value 形式的转换是相同的。
-
T (&array)[N] 中的括号是为了防止编译器按预期将& 绑定到T 而不是array。
- 括号的特殊用途通常是从上下文中推断出来的,但在变量声明和函数原型之间可能会出现一些问题。
希望这会有所帮助!