2012-01-02 43 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