2012-01-26 34 views
3

考慮下面的類:是否可以根據方法簽名中是否存在某個參數來將模板專門化?

class MyClass 
{ 
public: 
    template<class T> typename T::result_type apply(T& func) 
    { 
    if (is_int()) 
    { 
     return func(int(0)); 
    } 
    return func(double(0)); 
    } 
    ... 
}; 

(代碼看起來不是非常有用的,但它只是一個人爲的樣本來證明我的觀點)

無論如何,一個典型的仿函數將是這樣的:

struct MyFunc 
{ 
    typedef void result_type; 
    template<class V> void operator()(V) 
    { 
    // do something 
    } 
}; 

而且人會使用它,像這樣:

MyClass c; 
MyFunc f; 
c.apply(f); 

我的問題是 - 可以將MyClass::apply改爲識別功能函數的一個稍微不同的版本,除了原來的一個,例如期望調用者對象引用與所有其他參數一起傳遞這樣的:

struct MyFuncEx 
{ 
    typedef void result_type; 
    template<class V> void operator()(const MyClass& caller, V) 
    { 
    // do something 
    } 
}; 

所以,下面的代碼將編譯過:

MyClass c; 
MyFunc f; 
c.apply(f); 
MyFuncEx f2; 
c.apply(f2); 

作爲獎勵,我想編譯如果函子同時包含超載,失敗也就是下面要失敗編譯:

struct MyFuncSmartAss 
{ 
    typedef void result_type; 
    template<class V> void operator()(V) 
    { 
    // do something 
    } 
    template<class V> void operator()(const MyClass& caller, V) 
    { 
    // do something 
    } 
}; 

... 

MyClass c; 
c.apply(MyFuncSmartAss()); 

但是,只要較長的重載佔優先於較短的重載並不重要。

+0

的boost :: bind()的是你的朋友 –

+0

而且??????????? – mark

+0

有了boost :: bind,你可以承受一個'operator()'的重載,並決定調用網站在'caller'上創建一個閉包來提供一個'operator()',即使在第二個案件。 –

回答

3

這真的取決於您是否擁有C++ 11。這應該解決C++ 11(*)的過載問題:

class MyClass { 
private: 
    int _int; 
    double _double; 

public: 
    template <typename F> 
    auto apply(F& f) -> decltype(f(_int), f(_double)) { 
    if (is_int()) { return f(_int); } 
    return f(_double); 
    } 

    template <typename F> 
    auto apply(F& f) -> decltype(f(*this, _int), f(*this, _double)) { 
    if (is_int()) { return f(*this, _double); } 
    return f(_double) 
    } 

}; 

它是如何工作的?

  • 卸下不適於重載:與decltype後行返回型規範創建一個未計算的上下文。編譯器執行正則表達式的重載解析,但只關心類型。如果發生錯誤(operator()f存在),那麼我們就打SFINAE這種超負荷的apply被丟棄
  • 歧義如果兩個工作:如果兩個重載是合適的(因爲F同時提供運營商),則調用不明確

(*)我不太確定後行返回類型規格的正確性,更具體的使用this_arg。鏗鏘3.0和gcc 4.5.2錯誤。這可以解決,只是得到更多的冗長。

// first 
decltype(f(0), f(0.0)) 

// second 
decltype(f(std::declval<MyClass>(), 0), f(std::declval<MyClass>(), 0.0)) 

。在ideone與此變通措施:

編輯:應對int/double要求。

+0

我認爲不允許在尾部返回類型中使用'this'是標準中的缺陷(因爲同樣沒有成員)。不過,我可能會犯錯。 – Xeo

+0

@Xeo:沒關係啊,我沒有n3290對這種或那種方式,證明了互聯網搜索發現任何東西......沒用:) –

+0

我需要閱讀C++ 11功能概述,以瞭解你的答案。顯然,在過去的6年裏,很多事情都發生了變化...... – mark

相關問題