2017-03-05 94 views
1

是否可以根據模板參數的值有條件地編譯函數中的語句?例如:C++根據模板參數值更改成員函數定義

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>))不關心的功能。

我特別注意的應用程序是一個觀察者,對於某些類型,我只希望觀察者得到通知,如果該值實際發生更改,並且對於其他類型,我希望始終通知觀察者(以及對於那些類型I不想定義一個!=運算符)。

這可能沒有兩個單獨的類嗎?

回答

2

這可能沒有兩個單獨的類嗎?

是的。如果你不希望你的專業類,以避免重複的代碼,你可以使用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運行。

+0

這太好了。我曾看過enable_if,但IMO在cppreference.com上的文檔相當難以理解,並且聽起來好像不適合這樣(這可能是因爲我不太瞭解SFINAE的工作原理) –

+0

實際上你介意添加一個簡單的解釋,說明enable_if_t給你的只是enable_if,或許它是如何工作的?再次我看了,但我很快就來了。 –

+0

@schrödinbug你可以在這裏找到很多例子。比我能做的更好解釋! ;-) – skypjack

0

你在找什麼叫做'模板專業化'。

你將不得不專門化你的模板。定義你的基本模板,如上文後,將繼續並定義其專業化:

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

    // ... 

然後,您可以繼續並定義從無到有整個subject類,使得無論你更改的需要,爲的情況下第二個模板參數是true(或false,如果這就是你需要專門)。你可以刪除東西,或添加東西,或完全改變它們。專門化的類可以有不同的類成員,方法或相同的類方法,但其工作方式完全不同。

重要的是要明白,你現在定義了整個班級,而不僅僅是不同的位。如果這個類只有一個小方面需要專門化,那當然會產生一堆重複的代碼;所以經常需要重構它,把不同的位放到一個輔助類或函數中,並且只專注於不同的位。

即將到來的C++ 17標準還有其他一些替代方案來模板專門化;但專業化傳統上是人們學習的第一件事情,對於這種情況。所以,在開始討論C++ 17中的新東西之前,您應該先討論模板特化的章節,並將其放在第一章中。

+0

我曾看過專業化,但正如你所說,它會需要大量的重複,我不認爲它會允許一個功能,一般採用主題(即無論chk是真是假)。 )我認爲你必須重載這個函數。嗯。你指的是C++ 17中的哪些特性? –

+0

您應該重讀我的第二段的後半部分。就C++ 17而言,我指的是[constexpr if](http://en.cppreference.com/w/cpp/language/if#Constexpr_If)。 –