2013-08-03 35 views
0

我有一個模板函數的類:代理模式可以適應模板功能嗎?

了foo.h:

class Foo { 
public: 
    int some_function(); 
    bool some_other_function(int a, const Bar& b) const; 

    template<typename T> 
    int some_template_function(const T& arg); 
}; 

template<typename T> 
int Foo::some_template_function(const T& arg){ 
    /*...generic implementation...*/ 
} 

現在我走到一個地步,我希望能夠通過代理類來訪問富,如在Proxy design pattern中那樣。


直觀地說,我想重構如下(下面的代碼是不正確的,但它表達了我的 「理想化」 API):

FooInterface.h:

class FooInterface { 
public: 
    virtual int some_function()=0; 
    virtual bool some_other_function(int a, const Bar& b) const=0; 

    template<typename T> 
    virtual int some_template_function(const T& arg)=0; 
}; 

FooImpl.h:

#include "FooInterface.h" 

/** Implementation of the original Foo class **/ 
class FooImpl : public FooInterface { 
public: 
    int some_function(); 
    bool some_other_function(int a, const Bar& b) const; 

    template<typename T> 
    int some_template_function(const T& arg); 
}; 

template<typename T> 
int FooImpl::some_template_function(const T& arg){ 
    /*...generic implementation...*/ 
} 

FooProxy.h:

#include "FooInterface.h" 

class FooProxy : public FooInterface{ 
protected: 
    FooInterface* m_ptrImpl; // initialized somewhere with a FooImpl*; unimportant in the context of this question 
public: 
    int some_function() 
     { return m_ptrImpl->some_function(); } 
    bool some_other_function(int a, const Bar& b) const 
     { return m_ptrImpl->some_other_function(a,b); } 

    template<typename T> 
    int some_template_function(const T& arg) 
     { return m_ptrImpl->some_template_function(arg); } 
}; 

但這個代碼悲慘的失敗了。

首先,FooImpl無法編譯,因爲類模板函數不能是虛擬的。

更重要的是,即使我玩弄了some_template_function的定義,即使我將它重新定位到具體的課程或其他陪審團索具,它仍然會對整個首先是代理類,因爲模板代碼需要在標題中定義幷包含在內。這將迫使FooProxy.h包括FooImpl.hFooImpl.h需要所有的實施細節和文件,包括實施some_template_function必需的。因此,如果我使用代理模式來模糊實現細節,將自己與具體實現相隔離,並避免不必要的文件包含,那麼我的運氣不好。

有沒有辦法將代理模式或其某些變體應用於具有模板函數的類?或者在C++中這是不可能的?


語境:此刻,我想提供一組具有預先存在的類,內置日誌機制代理訪問。我爲此日誌使用的唯一API使用可變參數模板,因此無法預測將要使用的參數組合。我希望使用代理的實現和客戶端之間的分離儘可能地乾淨,並且我需要儘量減少從客戶端到實現的依賴關係,但我確實需要它們寫入相同的日誌。

但是,我對這個問題感興趣超出了我的眼前的問題。令我感到困惑的是,模板將這樣的洞捅入了主要的設計模式,並且我沒有發現這個問題在任何地方都能解決。

+0

是的,如果你在編譯時知道你想要什麼,有一種方法。這個味道有點像[xy問題](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem),所以你可以詳細說明你正在嘗試做什麼如何?如果無法預測可能需要實例化模板的所有類型,則無法隱藏模板實現,否則可以顯式實例化模板以獲取所需的類型。 – mars

+0

@mars:夠公平的;我試圖將問題簡化爲最簡單的形式。我會在某些情況下進行編輯。 – Ziv

+1

對不起,但我沒有想出如何使用模板方法編寫代理的解決方案,它不會將原始模板代碼放在標題中(預編譯標題有幫助嗎?)。除了你的問題之外,編寫一個代理'template class proxy {Implementation * m_ptrImpl; ...};'只要模板方法可用或顯式實例化,就可以以你期望的方式工作。 [如何在C++中實現虛擬模板功能](http://stackoverflow.com/questions/5871722/how-to-achieve-virtual-template-function-in-c)可能很有趣,暗示訪問者模式。 – mars

回答

2

具有模板化接口的類的包裝器/代理將始終要求在調用包裝器的代碼的頭文件中可見模板類的定義。這是因爲爲模板化接口生成的代碼取決於它所調用的參數的類型。

如果你堅持現有的模板實現FooImpl,那麼作爲@mars在評論中寫道,你唯一的選擇是:

template <class Implementation> 
class FooProxy 
{ 
    Implementation * m_ptrImpl; 
    //... 
}; 

如果你可以改變現有的實現,理想的解決辦法是重構模板化方法並將它們分成兩層;一層依賴於參數類型,另一層依賴於參數類型。現有方法中取決於參數類型的代碼在所有實現中都應該相同,因此可以將此圖層移入抽象接口類的方法中。剩下的代碼不依賴於參數類型,可以留在實現類的非模板化方法中,這意味着實現細節可以隱藏在.cpp文件中。

下面是一個例子,基於對支持編寫任意類型的日誌的情景:

LogInterface.h

class LogInterface { 
public: 
    template<typename T> 
    void write(const T& arg) 
    { 
     // converts from 'T' to array of characters. 
     // calls non-template 'write' as many times as necessary. 
    } 

    virtual void write(const char* p, std::size_t n)=0; 
}; 

LogImpl.h

#include "LogInterface.h" 

/** Implementation of the original Log class **/ 
class LogImpl : public LogInterface { 
public: 
    void write(const char* p, std::size_t n); 
}; 

LogProxy.h

#include "LogInterface.h" 

class LogProxy : public LogInterface{ 
protected: 
    LogInterface* m_ptrImpl; // initialized somewhere with a LogImpl* 
public: 
    void write(const char* p, std::size_t n) 
     { m_ptrImpl->write(p, n); } 
};