这些带有函数签名的模板特化如何工作?

时间:2014-01-24 17:45:07

标签: c++ templates

阅读了很多关于模板,模板专业化和部分专业化的文章后,我仍然无法理解以下模板巫术的工作方式和原因。

template <class T> class Signal;
template <class Arg, class Ret>
class Signal<Ret (Arg)> {
  typedef std::function<Ret (Arg)> Callback;
};

int main() {
  Signal<void (int x)> signal;
}

我很清楚代码的作用以及如何利用它,我只是无法理解为什么以及如何使用它。编译器如何解释包含空格和括号的特化参数,例如class Signal<Ret (Arg)>void (int x)如何/为何匹配专业化class Signal<Ret (Arg)>?为什么template <class Arg, class Ret>甚至是必要的?为什么不在“普通”专业化中使用<>class Argclass Ret的顺序似乎不重要,为什么?

如果这些问题没有任何意义,我很抱歉。如果他们不这样做,请不要直接回答他们。我只想了解上述代码的工作原理和原因。感谢。

2 个答案:

答案 0 :(得分:2)

具有单个模板参数的模板的定义:

template <class T> class Signal;

使用具有返回值(或void)和参数的函数来专门化模板:

template <class R, class A>
class Signal<R (A)> {
  typedef std::function<R (A)> Callback;
};

使用具有返回值(或void)和两个参数的函数来专门化模板:

template <class R, class A0, class A1>
class Signal<R (A0, A1)> {
  typedef std::function<R (A0, A1)> Callback;
};

等等......

即使每个专业化都是具有多个参数的模板,它指的是函数签名的单个模式。 “普通”专业化不能描述一组功能签名,而只能描述一个:

template <>
class Signal<void (int)> {
  typedef std::function<void (int)> Callback;
};

注意:只有专业化中模板参数的顺序(例如:信号&lt; R(A)&gt;)是相关的。

答案 1 :(得分:2)

问题是void(int x)是单一类型,即采用int并返回void的函数类型(此处忽略参数名x)类型绑定到T中的Signal。但是这种情况有一个专门化,所以它被选中,Ret被绑定到voidArgint。顺序与模板aragument list 中的无关,但无论你在专门的参数中使用它们的位置都很重要,因为传递的参数将被绑定到不同的方式。

对于数组类型也是如此:

template <typename T>
struct C;

template <typename Element, std::size_t size>
struct C<Еlement[size]> {};

int main() {
    C<int[42]> c;
}

您所谓的“正常”专业化实际上名为完全专业化,因为它们不需要提供其他参数来形成类型,因此空模板参数名单。您的示例和上面的示例称为部分特化,也可以用于其他模板:

template <typename T, int size>
struct Array {};

template <typename Element, std::size_t size>
struct C<Array<Еlement, size>> {};

int demo() {
    C<Array<int, 10>> a;
}