重载函数内部的函数重载

时间:2019-07-16 08:52:24

标签: c++ templates c++14 variadic-templates

我正在使用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组合在一起?

5 个答案:

答案 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()(创建一个特殊的无参数包装器)。

相关问题