簡體   English   中英

如何專門化具有多個參數的功能模板?

[英]How to specialize a function template with more than 1 parameter?

考慮以下模板成員函數:

template<typename E, typename N, typename P>
void Node::connectEvent( const bool( N::*fn )( const P& ), N *inst )
{
    // Obtain unique event ID based on type.
    size_t eventId = typeid( E ).hash_code();

    // Actual code wraps the function returned from std::bind, 
    // but for this example let's assume we can store it directly. 
    mCallbacks[eventId] = std::bind( fn, inst, std::placeholders::_1 );
}

我希望能夠通過以下方式調用此函數:

connectEvent<MouseDownEvent>( &MyNode::mouseDown, this );

,其中回調函數定義為:

bool MyNode::mouseDown( const MouseDownEvent &event );

,甚至使用基類作為參數,這就是為什么我在模板中具有單獨的事件類型E和參數類型P的原因:

bool MyNode::mouseDown( const Event &event );

我對此也需要支持:

connectEvent<DrawEvent>( &MyNode::draw, this );

,其中回調函數定義為:

bool MyNode::draw();

問題 :為了支持后者,我想專門針對參數P為空的情況的connectEvent函數,因為它需要對std::bind進行不同的調用。 我嘗試了許多不同的方法,包括在基本模板上使用enable_ifis_void的組合,但是沒有進行編譯,因此我必須做錯了一些,並且在這一點上采用了反復試驗。

在大多數情況下,Visual Studio 2015編譯器會抱怨“非法使用顯式模板參數”。

這是我認為可以使用的代碼版本,但沒有奏效:

template<typename E, typename N>
void Node::connectEvent<E,N,void>( const bool( N::*fn )(void), N *inst )
{
    size_t eventId = typeid( E ).hash_code();
    mCallbacks[eventId] = std::bind( fn, inst );
}

為了使之成為可能,我應該在代碼中進行哪些更改?

您不能部分專門化功能模板。 在您的情況下,您可以僅使用兩個模板參數定義第二個過載模板。

template<typename E, typename N, typename P>
void Node::connectEvent( const bool( N::*fn )( const P& ), N *inst ) { ...}

template<typename E, typename N>
void Node::connectEvent( const bool( N::*fn )(), N *inst ) { ...}

無論如何,專業化功能模板通常不是一個好主意。 解決方法是定義一個模板函數並在內部分派給可以部分專門化的模板類:

template<typename E, typename N, typename P> struct C
{
    static void connectEvent(const bool( N::*fn )( const P& ), N *inst)
    {
        size_t eventId = typeid( E ).hash_code();
        mCallbacks[eventId] = std::bind( fn, inst );
    }

};

 template<typename E, typename N> struct C<E,N,void> {
    ... specialize ...
 };

template<typename E, typename N, typename P>
void Node::connectEvent( const bool( N::*fn )( const P& ), N *inst ) 
{
    C<E,N,P>::connectEvent(fn, inst);
}

template<typename E, typename N>
void Node::connectEvent( const bool( N::*fn )(), N *inst ) 
{
    C<E,N,void>::connectEvent(fn, inst);
}

多虧了這里給出的答案,尤其是TC的話,我才意識到問題出在兩個函數的結合上:即使我們可以編寫兩個有效的版本,編譯器也無法正確區分它們,因為它將void視為參數,並始終嘗試構造第一個版本。 然后,它報告嘗試使用const void &param的錯誤。

唯一有效的解決方案是為connectEvent函數使用其他名稱,例如:

template<typename E, typename N>
void Node::connectVoidEvent( const bool( N::*fn )( ), N *inst );

,這樣編譯器就不會對我要使用哪個版本感到困惑。 不過,我可能不會使用它,而是始終將單個參數用作回調方法。

對於它的價值:我也嘗試這樣做,將問題轉移到對std::bind的調用上,但無法弄清楚從那里去哪里:

template<typename E, typename F, typename N>
void Node::connectEvent( const F &fn, N *inst )
{
    // F has type:          (__thiscall MyNode::*)(void)
    // or something like:   (__thiscall MyNode::*)(const Event&)

    size_t eventId = typeid( E ).hash_code();

    // How will the compiler know the number of parameters of F,
    // and whether or not to use placeholders?
    mCallbacks[eventId] = std::bind( fn, inst, std::placeholders::_1 );
}

但這是一個不同的問題。 無論如何,感謝大家的投入。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM