4

在這種測試代碼專門的模板:的函數簽名

#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;

爲什麼我必須指定它?

+0

因爲你必須有一個主模板才能夠專門化一個模板。在這種情況下,主模板未實現。 – Praetorian

+0

你不需要。如果您願意,您可以使用「T」和「U」使主模板參數化。這只是不夠靈活。 –

回答

2

您正在創建一個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)類型相結合,以專門用於該類。

3

你不要做你在做什麼,但它是最靈活的方法。與特殊化一個參數模板是這樣的:

  • 的模板參數化的一種類型...

    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任何我們喜歡的函數類型。相比之下,第二個示例中的直接模板與函數簽名的細節錯綜複雜,並且不容易被推廣。