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,因为 floattypename 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 为参数的函数的指针。