【发布时间】:2012-01-02 00:51:25
【问题描述】:
我有一个带有一些可选模板参数的类:
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(...)) 之类的东西)。
【问题讨论】:
-
你确定这个模板实例化是瓶颈吗?
-
你确定有 3 个
foo实例化了吗?我不明白他们为什么会这样。我只看到来自foo_runner<int, my_option1_t, my_option2_t>::run()的实例化。
标签: c++ performance templates fluent-interface