用于函数签名的专用模板

Specialized template for function signature

本文关键字:专用 函数 用于      更新时间:2023-10-16

在该测试代码中:

#include <string>
#include <iostream>
using namespace std;
template <typename T> class Signal;
template <typename T, typename U>
class Signal<T (U)>
{
public:
  Signal<T (U)>(T (*ptr)(U))
  {
  }
};
void Print(string const& str)
{
  cout << str << endl;
}
int main(int argc, char *argv[])
{
  Signal<void (string const&)> sig = &Print;
  return 0;
}

为什么我必须写template <typename T> class Signal;

为什么我必须指定它?

您不必做您正在做的事情,但这是最灵活的方法。具有专用化的单参数模板如下所示:

  • 一种类型上参数化的模板...

    template <typename> struct Foo;
    
  • 。但它只为函数类型定义:

    template <typename R>
    struct Foo<R()> { /* ... */ };
    template <typename R, typename A1>
    struct Foo<R(A1)> { /* ... */ };
    template <typename R, typename ...Args>
    struct Foo<R(Args...)> { /* ... */ };
    

另一种方法是对函数的签名进行硬编码:

  • 存储单参数函数的函数指针的类模板:

    template <typename R, typename A>
    struct Bar
    {
        R (*fp)(A);
        Bar(R(*f)(A)) : fp(f) { }
        // ...
    };
    

如您所见,第一种方法要通用得多,因为我们可以针对我们喜欢的任何函数类型专门Foo。相比之下,第二个示例中的直接模板与函数签名的细节错综复杂地联系在一起,不容易概括。

您正在创建Signal的专用化,它将任意类型TU组合成T(U)形式。这被放在一起作为专用化Signal<T(U)>:参数中只有一个类型,这就是为什么我们向前声明Signal只采用一种类型T。如果没有该声明,这是不可能的。

下面是一个简单的示例:

template <typename T> struct A;
template <typename T, typename U> struct A<T(U)> {
};
int main() {
    A<void(int)> a;
}

voidint类型分别绑定到TU的类型。这被组合到A的主要声明中使用的类型void(int)中,以专门化类。