C++模板<R(*)(T)>含义
C++ template <R(*)(T)> meaning
以下模板在 C++ 中的作用是什么?
template <class R, class T>
struct my_type<R(*)(T)> { typedef T type; };
具体来说,* 在这种情况下代表什么?
在此上下文中,它使模板特化引用指向函数的指针,该函数被声明为接受类型为 T
的单个参数,并且 return 类型为 [=12] 的值=].专业化提取参数类型并将其作为 typedef 提供。
示例 (demo):
#include <iostream>
#include <type_traits>
int foo(float);
template <typename T>
struct my_type;
template <class R, class T>
struct my_type<R(*)(T)> { typedef T type; };
int main() {
std::cout
<< std::is_same<
float,
typename my_type<decltype(&foo)>::type
>::value
<< "\n";
return 0;
}
这会输出 1
,因为 float
和 typename my_type<decltype(&foo)>::type
都引用相同的类型——decltype(&foo)
是类型 int (*)(float)
,它与特化相匹配R(*)(T)
.
上面 cdhowie 的回答很好,但我觉得它更多地解释了模板专业化的作用,而不是回答具体问题:*
在 [=19 中代表什么=].
为此,我们需要了解一下我们如何在 C++ 的类型系统中指定类型。如果您已经知道大部分内容或全部内容,请不要生气,但我认为如果我只是从基础开始,我可以最好地解释它。如果不是你,也许其他人可以从中学习(我自己对来自 Pascal 的 C(++) 类型系统感到很困惑 :))。如果你只是想要答案,那就是这个post.
的最后一句
假设我们要声明一个名为 foo
的变量,类型为 int
。
int foo;
嗯,这很简单。现在,让我们将其更改为 3 个整数的数组:
int foo[3];
了解我们在这里所做的事情很重要。您可能会认为数组说明符只是放在最后,但事实并非如此。因为,要声明一些东西的数组,我们需要在命名我们的变量 或本例中的 foo
的标识符之后添加方括号 。当您想将此声明扩展为 2 × int[3]
:
的数组时,这一点就变得很清楚了
int foo[2][3];
因此,通过在声明 int foo[3]
中用 foo[2]
替换 foo
,我们得到 int foo[2][3]
。这就是为什么 foo
是一个 数组 2 × [数组 3 × int
]。当我们添加括号时(实际上我们被允许这样做),这一点变得更加明显:
int foo; // [int]
int (foo[3]); // array of 3×[int]
int ((foo[2])[3]); // array of 2×[array of 3×[int]]
C++ 使用类似的指针系统。要声明指向某物的指针,在标识符前加上 *
.
int foo; // [int]
int (*foo); // pointer to [int] (same as: int *foo)
int (*(*foo)); // pointer to [pointer to [int]] (same as: int **foo)
因此,我们在每一行中用 (*foo)
替换了 foo
。
这就是事情变得有趣的地方。对于指针,我们需要在标识符前加上 *
前缀,对于数组,我们需要在标识符前加上 post 前缀 []
,那么,int *foo[3]
是什么意思呢?事实证明,int *foo[3]
被解析为 int *(foo[3])
。因此,它是一个 数组,包含 3 × [指向 int
] 的指针。要获得指向 [array of 3 × int
] 的 指针,我们需要做:int (*foo)[3]
int *(foo[3]); // array of 3×[pointer to [int]] (same as: int *foo[3])
int (*foo)[3]; // pointer to [array of 3×[int]]
现在,为了回答您的问题,我们需要查看函数声明。这实际上类似于数组。要声明函数,请在标识符后面添加括号和参数列表:
int foo; // [int]
int (foo()); // function returning [int] (same as: int foo())
现在我们也可以套用上面的规则了:
int foo; // [int]
int (foo()); // function returning [int] (same as: int foo())
int ((*foo)()); // pointer to [function returning [int]] (same as: int (*foo)())
int ((*(foo[2]))()); // array of 2×[pointer to [function returning [int]]] (same as: int (*foo[2])())
要命名没有标识符的类型,只需擦除标识符即可。所以上面例子中第三个 foo
的类型就是 int(*)()
。请注意,此处的括号是强制性的。如果它是 int*()
,它将是一个 函数返回 [指向 [int]].
的函数
Tip: to figure out the type of something, use a bottom-up approach, starting at the identifier (or where the identifier would be), working outward, using the following annotations: *
stands for "pointer to...", []
for "array of..." and (x)
for "function taking (x) and returning...". As a rule of thumb: if there are no parentheses, the right hand side goes before the left hand side.
现在我们可以回答您的问题了:R(*)(T)
中的 *
代表:指向以 T 作为参数且 returns 以 R 为参数的函数的指针。
以下模板在 C++ 中的作用是什么?
template <class R, class T>
struct my_type<R(*)(T)> { typedef T type; };
具体来说,* 在这种情况下代表什么?
在此上下文中,它使模板特化引用指向函数的指针,该函数被声明为接受类型为 T
的单个参数,并且 return 类型为 [=12] 的值=].专业化提取参数类型并将其作为 typedef 提供。
示例 (demo):
#include <iostream>
#include <type_traits>
int foo(float);
template <typename T>
struct my_type;
template <class R, class T>
struct my_type<R(*)(T)> { typedef T type; };
int main() {
std::cout
<< std::is_same<
float,
typename my_type<decltype(&foo)>::type
>::value
<< "\n";
return 0;
}
这会输出 1
,因为 float
和 typename my_type<decltype(&foo)>::type
都引用相同的类型——decltype(&foo)
是类型 int (*)(float)
,它与特化相匹配R(*)(T)
.
上面 cdhowie 的回答很好,但我觉得它更多地解释了模板专业化的作用,而不是回答具体问题:*
在 [=19 中代表什么=].
为此,我们需要了解一下我们如何在 C++ 的类型系统中指定类型。如果您已经知道大部分内容或全部内容,请不要生气,但我认为如果我只是从基础开始,我可以最好地解释它。如果不是你,也许其他人可以从中学习(我自己对来自 Pascal 的 C(++) 类型系统感到很困惑 :))。如果你只是想要答案,那就是这个post.
的最后一句假设我们要声明一个名为 foo
的变量,类型为 int
。
int foo;
嗯,这很简单。现在,让我们将其更改为 3 个整数的数组:
int foo[3];
了解我们在这里所做的事情很重要。您可能会认为数组说明符只是放在最后,但事实并非如此。因为,要声明一些东西的数组,我们需要在命名我们的变量 或本例中的 foo
的标识符之后添加方括号 。当您想将此声明扩展为 2 × int[3]
:
int foo[2][3];
因此,通过在声明 int foo[3]
中用 foo[2]
替换 foo
,我们得到 int foo[2][3]
。这就是为什么 foo
是一个 数组 2 × [数组 3 × int
]。当我们添加括号时(实际上我们被允许这样做),这一点变得更加明显:
int foo; // [int]
int (foo[3]); // array of 3×[int]
int ((foo[2])[3]); // array of 2×[array of 3×[int]]
C++ 使用类似的指针系统。要声明指向某物的指针,在标识符前加上 *
.
int foo; // [int]
int (*foo); // pointer to [int] (same as: int *foo)
int (*(*foo)); // pointer to [pointer to [int]] (same as: int **foo)
因此,我们在每一行中用 (*foo)
替换了 foo
。
这就是事情变得有趣的地方。对于指针,我们需要在标识符前加上 *
前缀,对于数组,我们需要在标识符前加上 post 前缀 []
,那么,int *foo[3]
是什么意思呢?事实证明,int *foo[3]
被解析为 int *(foo[3])
。因此,它是一个 数组,包含 3 × [指向 int
] 的指针。要获得指向 [array of 3 × int
] 的 指针,我们需要做:int (*foo)[3]
int *(foo[3]); // array of 3×[pointer to [int]] (same as: int *foo[3])
int (*foo)[3]; // pointer to [array of 3×[int]]
现在,为了回答您的问题,我们需要查看函数声明。这实际上类似于数组。要声明函数,请在标识符后面添加括号和参数列表:
int foo; // [int]
int (foo()); // function returning [int] (same as: int foo())
现在我们也可以套用上面的规则了:
int foo; // [int]
int (foo()); // function returning [int] (same as: int foo())
int ((*foo)()); // pointer to [function returning [int]] (same as: int (*foo)())
int ((*(foo[2]))()); // array of 2×[pointer to [function returning [int]]] (same as: int (*foo[2])())
要命名没有标识符的类型,只需擦除标识符即可。所以上面例子中第三个 foo
的类型就是 int(*)()
。请注意,此处的括号是强制性的。如果它是 int*()
,它将是一个 函数返回 [指向 [int]].
Tip: to figure out the type of something, use a bottom-up approach, starting at the identifier (or where the identifier would be), working outward, using the following annotations:
*
stands for "pointer to...",[]
for "array of..." and(x)
for "function taking (x) and returning...". As a rule of thumb: if there are no parentheses, the right hand side goes before the left hand side.
现在我们可以回答您的问题了:R(*)(T)
中的 *
代表:指向以 T 作为参数且 returns 以 R 为参数的函数的指针。