我正在使用C++14
(而且还很新)。我有3个重载函数func
,其中另一个重载函数do_something
根据其父函数(func
)被调用。
int func(int a) {
bar(a);
foo();
}
int func(int a, float b) {
bar(a);
do_something(b);
foo();
}
int func(int a, float b, char c) {
bar(a);
do_something(b, c);
foo();
}
我看到func
中的功能几乎相同,除了调用了do_something
的哪个版本。我有什么方法可以使这个泛型并将所有func
组合在一起?
答案 0 :(得分:3)
首先,将func
设为接受参数包的模板。 int a
参数,对bar
的调用和对foo
的调用一直都在那儿,所以很简单。现在,我们为do_something
添加一个占位符。
template <class ...Args>
int func(int a, Args&&... other)
{
bar(a);
// somehow call do_something and do the right thing
foo();
return 0;
}
您要像以前一样实例化并调用上述模板:
func(42);
func(42, 1.f);
func(42, 1.f, 'A');
现在让我们解决对do_something
的调用。如果您只是将其添加到新的func
模板的中间,
do_something(std::forward<Args>(other)...);
这拒绝为func(42)
进行编译,即只有一个参数的情况。因此,我们需要为此提供特殊情况。在do_something
的另一个间接级别上实现此目标的一种方法:
// No additional argument case, does nothing:
void do_something_wrapper() {}
// The other two cases
template <class ...Args>
void do_something_wrapper(Args&&... args)
{
do_something(std::forward<Args>(args)...);
}
现在,func
函数模板中的占位符应为:
do_something_wrapper(std::forward<Args>(other)...);
答案 1 :(得分:2)
第一步是使用可变参数模板来获取要转发给do_something
的部分:
template<class ... Args>
int func(int a, Args... args)
{
bar(a);
do_something(std::forward<Args>(args)...)
foo();
}
但是现在您已经失去了func的参数类型。因此,如果这是一个问题,您将不得不找到一种方法来再次测试它们。
答案 2 :(得分:1)
尽管我本人可能会接受generic_opto_guy的回答,但他是正确的指出您会丢失界面中的类型。根据您的情况,您可能需要保留它。
在这种情况下,您可以轻松地将其修改为类似于以下内容的内容:
namespace details {
template<class ... Args>
int func_impl(int a, Args &&... args)
{
bar(a);
do_something(std::forward<Args>(args)...)
foo();
}
}
int func(int a) { return details::func_impl(a); }
int func(int a, float b) { return details::func_impl(a, b); }
int func(int a, float b, char c) { return details::func_impl(a, b, c); }
请注意,已将实现调整为使用perfect forwarding。在这种特殊情况下虽然不需要,但通常在将来可能遇到的转发情况下很有用。
同样,除非您绝对需要提供一个清晰的客户端代码接口,否则我将只执行第一个实现。
答案 3 :(得分:0)
其他答案是所问问题的通用回答,但是,如果您有c
的一些“备用”值,则可以这样写:
int func(int a) {
func(a, 0.0,'\001');
}
int func(int a, float b, char c = '\002') {
bar(a);
switch (c) {
case '\001':
break; // func(a)
case '\002':
do_something(b): // func(a, b)
break;
default:
do_something(b, c); // func(a, b, c)
break;
}
foo();
}
取决于应用程序,这可能会更简单。
答案 4 :(得分:0)
玩太晚了吗?
您标记了C ++ 14,但是,如果可以使用C ++ 17,则可以使用if constexpr
,
template <typename ... Ts>
int func (int a, Ts && ... ts)
{
bar(a);
if constexpr ( sizeof...(Ts) > 0u )
do_something(std::forward<Ts>(ts)...);
foo();
// and remember to return something of int
}
在C ++ 14中,您必须在某处复制某些内容。
或者您写两个func()
int func (int a)
{
bar(a);
foo();
// and remember to return something of int
}
template <typename ... Ts>
int func (int a, Ts && ... ts)
{
bar(a);
do_something(std::forward<Ts>(ts)...);
foo();
// and remember to return something of int
}
或者您添加无参数do_something()
void do_something ()
{ }
或者根据lubgr的建议,您通过包装器调用do_something()
(创建一个特殊的无参数包装器)。