2012-01-02 96 views
1

我有一些可選的模板參數類避免不必要的模板實例:在流暢的界面

struct option1_default_t {}; 
struct option2_default_t {}; 

template <typename T, 
      typename option1_t = option1_default_t, 
      typename option2_t = option2_default_t> 
class foo 
{ 
public: 
    foo(option1_t option1 = option1_t(), option2_t option2 = option2_t()); 

    void run(); 
}; 

和指定他們以下fluent interface

template <typename T, typename option1_t, typename option2_t> 
struct foo_runner 
{ 
    option1_t option1_; 
    option2_t option2_; 

    template <typename new_option1_t> 
    foo_runner<T, new_option1_t, option2_t> option1(new_option1_t new_option1) 
    { 
     return foo_runner<T, new_option1_t, option2_t>{new_option1, option2_}; 
    } 

    template <typename new_option2_t> 
    foo_runner<T, option1_t, new_option2_t> option2(new_option2_t new_option2) 
    { 
     return foo_runner<T, option1_t, new_option2_t>{option1_, new_option2}; 
    } 

    void run() 
    { 
     foo<T, option1_t, option2_t> f(option1_, option2_); 
     f.run(); 
    } 
}; 

template <typename T> 
foo_runner<T, option1_default_t, option2_default_t> make_foo() 
{ 
    return foo_runner<T, option1_default_t, option2_default_t>(); 
} 

這裏是如何流利的例子接口被使用:

struct my_option1_t { ... }; 
struct my_option2_t { ... }; 

int main() 
{ 
    make_foo<int>() 
     .option1(my_option1_t(...)) 
     .option2(my_option2_t(...)) 
     .run(); 
} 

這當然是一個簡化版本錫安;在我的真實代碼中有很多選項,在這個類的典型用法中,只有其中的一部分被指定,因此流暢接口的理由。

這個流暢的界面的問題是它引起不必要的模板實例化。例如,上面的示例實例化了foo三次:foo<int, option1_default_t, option2_default_t>,foo<int, my_option1_t, option2_default_t>,最後是foo<int, my_option1_t, my_option2_t>,這是我想要的。

這是有問題的,因爲foo是一個很大的類,並且實例化它的編譯時代很昂貴。

有沒有一種方法我可以改變流暢的界面的實施不改變接口如何使用使foo只實例化一次,最後的參數呢?

請注意,接口不變的要求 - 即我作爲使用流暢接口的例子所提供的完全相同的代碼,繼續保持不變 - 這是關鍵。如果沒有這個要求,我可以輕鬆地重寫流暢的接口來僅實例化foo一次(例如,我可以將接口更改爲run_foo(make_foo<int>().option1(...).option2(...)))。

+0

您確定此模板實例化是瓶頸嗎? – 2012-01-02 01:37:40

+2

你甚至確定有3個'foo'實例化的實例嗎?我不明白他們爲什麼會這樣。我只看到'foo_runner :: run()'的實例化。 – MSalters 2012-01-02 08:23:06

回答

1

我不認爲有多個foo實例(正如在MSalters的評論中指出的那樣)。如果你想驗證這一點,你可以爲foo創建專門的默認參數,當它們被實例化時會導致錯誤。顯然,這對實際生產版本來說並不好,但是這將證明沒有多個實例化。

一旦您確認foo的多個實例確實不是問題,問題就變成了:如何提高模板代碼的編譯時間?對此的答案通常是將代碼分解爲依賴於較少模板參數(如果有的話)的助手。這有點痛苦,但可以產生戲劇性的影響。避免常用模板的所有翻譯單元中的實例化也可能是有益的。在C++ 2011中,您可以使用extern模板與顯式實例相結合。在C++ 2003中,你必須專門化你想要的實例代碼。

+0

你是對的,在上面的代碼中沒有'foo'的多個實例化...在減少我的實際代碼的過程中出現了錯誤(它確實有多個'foo'的實例化,這一點從我在這個例子中從'foo'的兩個不同實例中得到了一個錯誤信息。我會調查。 – HighCommander4 2012-01-03 20:22:56