2013-07-19 51 views
6

C++允許非類型模板參數爲指針,包括函數指針,類型。我最近問了一個question這是什麼對我有用,這是一個跟進到one of the answers有沒有辦法推導一個函數指針模板參數的值?

是否可以從函數指針中推斷函數指針模板參數的?例如:

using VoidFunction = void(*)(); 

template <VoidFunction F> 
void templ(VoidFunction); 

... 

void func(); // a VoidFunction 

... 

templ<func>(func); // works, but I have to specify the template parameter explicitly 
templ(func);  // <-- I would like to be able to do this 

有沒有辦法讓這種扣除發生?從編譯器實現者的角度來看,在技術上似乎是可行的,只要函數參數可以在編譯時解析爲代碼中的函數即可。

如果您想知道背後的動機,請參閱this answer下的意見,特別是對std::bind()實施的可能優化。

編輯:我意識到我可以簡單地刪除函數參數並使用模板參數,如templ<func>()。我在函數參數中添加的唯一目的是試圖避免必須傳遞模板參數。

我想我真正想要的,是要還推導出函數指針的類型,如:

template <typename Function, Function F> 
void templ(/* something */); 

,然後能夠調用

templ(func); 

templ<func>(); 

並且具有類型和值從單一提及函數指針。

希望現在更有意義。

+0

完整模板參數列表,它怎麼能演繹呢?例如,我可以這樣做:'template void foo(std :: size_t i){int arr [N];/* fill */return arr [i];}'。如果我在碰巧可以完成這個演繹時偶然忘記模板參數,我肯定會想要一個錯誤。 – chris

+0

想一想,我不確定我是否理解爲什麼它需要作爲函數參數傳遞。不是'templ ();'夠了嗎? – chris

+0

@chris:對,我的問題沒有多少意義,請參閱我的編輯。 – HighCommander4

回答

2

函數的模板參數是從函數模板參數的類型中推導出來的。只有當該類型是允許的表單之一時,模板參數才能從類型推導出來。了允許的格式在[temp.deduct.type]指定

模板參數可以以幾種不同的上下文推導出,但在每種情況下,其在模板參數(稱之爲P)項規定的類型進行比較與一個實際的類型(稱爲A),並試圖找到將會使P的模板參數值(類型參數的類型,非類型參數的值或模板參數的模板)在替代推導值後(稱之爲A),與A兼容。

模板類型參數T,一個模板的模板參數TT或模板非類型參數i可以推斷出如果PA具有下列形式之一:

T 
cv-list T 
T* 
T& 
T[integer-constant] 
template-name (where template-name refers to a class template) 
type(*)(T) 
T(*)() 
T(*)(T) 
T type::* 
type T::* 
T T::* 
T (type::*)() 
type (T::*)() 
type (type::*)(T) 
type (T::*)(T) 
T (type::*)(T) 
T (T::*)() 
T (T::*)(T) 
type[i] 
template-name&lti> (where template-name refers to a class template) 
TT<T> 
TT<i> 
TT<>

其中(T)表示參數列表,其中至少一個參數類型包含T()表示參數列表,其中參數不包含T。類似地,<T>表示模板參數列表,其中至少一個參數包含T,<i>表示模板參數列表,其中至少一個參數包含i<>表示模板參數列表,其中參數不包含Ti

當僅考慮非類型模板參數,相關的形式是那些含有i

type[i] 
template-name&lti> (where template-name refers to a class template) 
TT<i>

因此,不可能直接從函數參數的值,推斷值函數指針。但是,如果函數參數具有指定形式之一,則可能推導出非類型模板參數的值。

以下代碼通過將非類型模板參數值包裝在名爲NonType的類模板中來解決這個問題。 f的參數形式爲template-name<i>,可以推導出其非類型模板參數的值。

template<typename T, T value> 
struct NonType {}; 

template<typename T, T value> 
void f(NonType<T, value>) 
{ 
} 

void g(); 

struct A 
{ 
    void f(); 
    int m; 
}; 

int i; 

#define MAKE_NONTYPE(value) NonType<decltype(value), (value)>() 

int main() 
{ 
    f(MAKE_NONTYPE(0)); // NonType<int, 0> 
    f(MAKE_NONTYPE(&g)); // NonType<void(*)(), &g> 
    f(MAKE_NONTYPE(&A::f)); // NonType<void(A::*)(), &A::f> 
    f(MAKE_NONTYPE(&A::m)); // NonType<int A::*, &A::m> 
    f(MAKE_NONTYPE(&i)); // NonType<int*, &i> 
} 

注意decltypeMAKE_NON_TYPE宏用在這裏只是爲了方便,以避免寫出來的NonType

相關問題