2014-12-10 61 views
0

我有下列模板:如何從模板中使用const或非const成員函數生成類?

template<typename Signature> 
class TypeErasedFunctor; 

template<typename R, typename... Args> 
class TypeErasedFunctor<R(Args...)> 
{ 
public: 

    virtual R operator()(Args... args) = 0; 
}; 

它可被用於產生接口類爲這樣函子:

using SemaphoreFunctor = TypeErasedFunctor<int(Semaphore&)>;

如可以看到的成員函數operator()是非常量。我想問以下問題 - 是否有任何選項來選擇是否const或非const變量應該不是這兩個產生的其它:

  • 使用SFINAE(可能與std::enable_if<>)和模板的其他參數,
  • 使用單獨的模板ConstTypeErasedFunctor
+1

對於這個特殊的問題,只是使它成爲'const',因爲按照慣例,函數應該是無狀態的,因此,不可變/常量。這就是'std :: function'所做的。您可以通過將非const函數作爲「可變」數據成員來避開派生類中的常量。 – 2014-12-10 21:52:31

+0

@MikaelPersson - 那麼,關於「無狀態」的部分,我不能同意(如果函數應該是無狀態的,與純函數相比有什麼收穫?),但是您能否詳細說明「將非const函數作爲可變數據成員「?我必須承認,問題的動機是需要修改從此模板派生的對象的內容(在某些情況下),而不是在非const對象上使用'operator()const'。 – 2014-12-10 22:00:08

+0

無狀態意味着任何兩個隨後的函數調用都會產生相同的效果和結果。通常情況下,函數作爲回調函數或作爲算法的輔助函數傳遞(例如,謂詞,比較函數等),其中未定義函數調用的頻率和時間,在這種情況下,它更可取如果它是無狀態的。然而,無狀態並不意味着「無參數」,這就是functor(callable obj)比函數指針更好的地方。通常,你需要一個*參數化的函子,而不是*有狀態的*函子。 – 2014-12-10 23:10:23

回答

3

可以兼得(常量和沒有常)相同的對象重載運營商的版本()。但是,如果你想輕鬆地只有一個選擇申報對象時,你可以使用類似的東西:

template<bool b, typename Signature> 
class TypeErasedFunctor; 

template<typename R, typename... Args> 
class TypeErasedFunctor<true,R(Args...)> 
{ 
    public: 
     virtual R operator() (Args... args) const = 0; 
}; 

template<typename R, typename... Args> 
class TypeErasedFunctor<false,R(Args...)> 
{ 
    public: 
     virtual R operator()(Args... args) = 0; 
}; 

template<bool b> 
using SemaphoreFunctor = TypeErasedFunctor<b,int(Semaphore&)>; 

後來,在客戶端代碼,你可以用剩下的一般的參數選擇:

SemaphoreFunctor<true> object_with_const_op; 
SemaphoreFunctor<false> object_with_no_const_op;