我有一个带有一些可选模板参数的类:
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 :(得分:1)
我不认为有foo
的多个实例化(正如MSalters的评论中指出的那样)。如果要验证这一点,可以为默认参数创建foo
的特化,这些参数在实例化时会导致错误。显然,这对于实际的生产版本并不好,但这可以证明没有多个实例化。
一旦验证了foo
的多个实例确实不是问题,问题就变成:如何改善模板化代码的编译时间?通常,答案是将代码分解为依赖于较少模板参数(如果有)的帮助程序。这有点痛苦,但可以产生戏剧性的影响。避免在常用模板的所有翻译单元中进行实例化也是有益的。使用C ++ 2011,您可以将extern模板与显式实例化结合使用。使用C ++ 2003,您必须专门化要预先实例化的代码。