2017-05-05 156 views
4

我試圖創建程序,只有當模板被實例化時(它將用於低級驅動程序初始化)纔會執行一些代碼。 現在我有以下解決方案。強制模板靜態成員實例

class Initializer 
{ 
public: 
    Initializer(){ 
     // This code is executed once 
    } 

    void silly() const{ 

    } 
}; 

template <class T> 
class Proxy{ 
protected: 
    static const Initializer init; 
}; 

template<class T> 
const Initializer Proxy<T>::init; 

template<class T> 
class MyTemplate : public Proxy<void>{ 
public: 
    static void myMethod1(){ 
     init.silly(); 

     // ... Something useful 
    } 

    static void myMethod2(){ 
     init.silly(); 

     // ... Something useful 
    } 
}; 

Initializer默認的構造函數只有在情況下,我打電話myMethod1()myMethod2()某處被執行。

但是有沒有辦法擺脫那些init.silly();行?

+0

「強制實例化:」和「檢查實例化」是兩個完全不同的事情。 –

+0

你是否想爲'Proxy'的每個實例創建'Initializer'?例如。如果你創建'Proxy '和'Proxy ',那麼'Initializer'會被構造兩次? – Pavel

+0

不,我只想創建一個'Initializer'實例。我將永遠繼承'代理'。 – valentin

回答

2

你的問題是,模板的成員沒有被實例化,除非被引用。

不需要調用init.silly(),你可以參考成員:

static void myMethod1(){ 
     (void)init; 

     // ... Something useful 
    } 

或者,如果你想init是絕對總是定義,你可以顯式實例吧:

template<> 
const Initializer Proxy<void>::init{}; 
+0

它更好,但仍需要額外的一行代碼。 如果我使用'init'的顯式實例化,即使未實例化MyTemplate,它的構造函數也會執行。情況並非如此。 – valentin

1

模板低級別的驅動程序初始化?..我會盡量使它儘可能C :)以確保確切的行爲。

你可以做這樣的事情或許是:

class Initializer 
{ 
public: 
    Initializer() { 
     // This code is executed once 
    } 
}; 

template <class T> 
class Proxy { 
protected: 
    Proxy() 
    { 
     static Initializer init; 
    } 
}; 

template<class T> 
class MyTemplate : public Proxy<void> { 
public: 
    void myMethod1() { 
     // ... Something useful 
    } 

    void myMethod2() { 
     // ... Something useful 
    } 
}; 

所有的代碼只使用靜態函數並沒有真正說明爲什麼你會用類和模板。通過我的更改,我創建了myMethod1myMethod2非靜態,Proxy()構造函數創建了Initializer一次。

請注意,由於所有模板混亂,您可能會在實例化代理模板時多次執行您的Initializer。你真的認真嗎?如果不是,則轉換爲清晰可讀的代碼,該代碼不會出現此意外結果。這也將是更好的維護和可讀性爲他人:

class Initializer 
{ 
    Initializer() { 
     // This code is executed once 
    } 
public: 
    void init() 
    { 
     static Initializer init; 
    } 
}; 


template<class T> 
class MyTemplate { 
public: 
    static void myMethod1() { 
     Initializer::init(); 
     // ... Something useful 
    } 

    static void myMethod2() { 
     Initializer::init(); 
     // ... Something useful 
    } 
}; 

這使得絕對清楚地表明Initializer將創建一次myMethod1myMethod2調用前。如果沒有任何東西叫你Initializer::init那麼Initializer的代碼應該在鏈接時被刪除。

+0

哦,是的!這更乾淨。它還不必擔心有關模板成員何時被實例化的詳細問題 - 這只是a)開發人員感到困惑的標準的黑暗角落; b)*編譯器*開發者偶爾會感到困惑。 –