簡體   English   中英

C ++根據模板參數值更改成員函數定義

[英]C++ Change member function definition based on template parameter value

是否可以基於模板參數的值在函數中有條件地編譯語句? 例如:

template<typename T, bool chk>
class subject
{
public:
    // the ideal case    
    void doSomething(T new_val)
    {
        if(chk)
        {
          if(new_val != val)
              //do_something only if new_val is different from val
        }
        else
        {
            //do_something even if new_val and val are equal
        }
    }


    //or if that's not possible, if chk = 0 use this method
    void doSomething(T new_val) 
    {
        //do_something even if new_val and val are equal
    }

    // and if chk = 1 use this method
    void doSomething(T new_val) 
    {
        if(new_val != val)
           //do_something only if new_val is different from val
    }

    T val;
};

捕獲是基於chk的值,我什至都不希望將if(new_val!=val)語句編譯到函數中(因為使用的每個T類型都必須定義!=運算符)。

我猜這種方法的一個缺點是foo<int,0>foo<int,1>是不同的類,因此不可能定義一個不在乎chk是0還是1的函數(比如watch(foo<int>) )。

我正在查看的應用程序專門是觀察者,對於某些類型,我只希望觀察者在值實際更改時得到通知,對於其他類型,我希望觀察者始終得到通知(對於那些我不希望的類型必須定義!=運算符)。

如果沒有兩個單獨的類,這是否可能?

如果沒有兩個單獨的類,這是否可能?

是的。 如果不想專門化您的類,以避免代碼重復,則可以使用以下示例中的sfinae表達式:

#include <type_traits>
#include <iostream>

template<typename T, bool chk>
struct subject {
    template<bool trigger = chk>
    std::enable_if_t<trigger>
    doSomething(T new_val) {
        if(new_val != val) {
            std::cout << "new_val != val" << std::endl;
        } else {
            std::cout << "new_val == val" << std::endl;
        }
    }

    template<bool trigger = chk>
    std::enable_if_t<not trigger>
    doSomething(T new_val) {
        std::cout << "who cares?" << std::endl;
    }

    T val;
};

int main() {
    subject<int, true> s1{0};
    s1.doSomething(0);
    s1.doSomething(1);
    subject<int, false> s2{0};
    s2.doSomething(0);
    s2.doSomething(1);
}

這個想法是在編譯時就為doSomething定義了正確的定義,它取決於模板參數chk的值。 另一個定義只是簡單地按預期丟棄,根本無法使用。
請注意,要使sfinae表達式起作用, trigger模板參數必須是成員函數模板的實際參數。 這就是為什么您必須這樣定義它的原因:

template<bool trigger = chk>
sfinae_expression_based_on_enable_if
doSomething(T new_val) { /* ... */ }

看到它在coliru上運行。

您正在尋找的被稱為“模板專業化”。

您將必須專門化您的模板。 在定義了基本模板之后,如上所述,您將繼續並定義其專業化:

template<typename T>
class subject<T, true>
{
public:

   // ...

然后,對於第二個模板參數為true (或false ,如果需要專門設置的話),您可以從頭開始定義整個subject類,並進行所需的任何更改。 您可以刪除,添加或完全更改它們。 專門的類可以具有不同的類成員,方法或相同的類方法,但是它們的工作方式完全不同。

重要的是要了解您正在定義整個類,而不僅僅是定義不同的位。 如果確實只需要對該類的一個較小方面進行專門化,那么這當然會導致一堆重復的代碼; 因此通常需要對其進行重構,將不同的位放入幫助器類或函數中,並僅對不同的位進行專門化處理。

即將到來的C ++ 17標准還提供了一些其他的模板專業化替代方法。 但是在這種情況下,傳統上,專業化是第一要學的東西。 因此,在繼續學習C ++ 17的新知識之前,您應該將C ++書籍放到討論模板專業化的章節中,並首先掌握其中的知識。

暫無
暫無

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

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