C ++模板<r(*)(t)>含义

时间:2018-01-06 21:27:38

标签: c++ templates generic-programming

以下模板在C ++中的作用是什么?

template <class R, class T>
struct my_type<R(*)(T)> { typedef T type; };

具体来说,*在这种背景下代表什么?

2 个答案:

答案 0 :(得分:3)

在此上下文中,它使模板特化引用一个指向函数的指针,该函数被声明为接受类型T的单个参数,并返回类型R的值。专门化提取参数类型并使其可用作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)匹配1}}。

答案 1 :(得分:0)

cdhowie上面给出了很好的答案,但我觉得它更能解释什么是模板专业化,而不是解释具体问题: *代表R(*)(T)

为此,我们需要看看我们如何在C ++的类型系统中指定类型。如果你已经了解了大部分或全部内容,请不要被冒犯,但我认为如果我从基础开始,我可以最好地解释它。如果不是你,也许其他人可以从中学习(我自己很困惑C(++)的类型系统,来自Pascal :))。如果你只想要答案,那就是这篇文章的最后一句话。

假设我们要声明一个名为foo的变量int

int foo;

嗯,这很容易。现在,让我们将其更改为3个整数的数组:

int foo[3];

重要的是要意识到我们在这里所做的一切。您可能会认为数组说明符只是最后一个,但事实并非如此。因为,为了声明某个数组,我们需要在命名变量的标识符之后添加括号,或者在这种情况下添加foo。当您想要将此声明扩展为2×int[3]

的数组时,这一点就变得清晰了
int foo[2][3];

因此,通过在foo声明中用foo[2]替换int foo[3],我们得到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)

这是事情变得有趣的地方。我们需要为标识符添加*作为指针的前缀,并使用[]为数组后缀,但是,int *foo[3]是什么意思?事实证明,int *foo[3]被解析为int *(foo[3])。所以,它是一个3×[指向int] 的指针的数组。要获得指向[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]] 的指针。

  

提示:要弄清楚某事物的类型,请使用自下而上的方法,从标识符(或标识符所在的位置)开始,向外工作,使用以下注释:{{ 1}代表“指向...的指针”,*表示“数组...”,[]代表“函数接收(x)并返回...”。根据经验:如果没有括号,右侧会在左侧之前。

现在我们可以回答你的问题:(x)中的*代表:一个指向函数的指针,该函数以T为参数并返回R。