简体   繁体   English

重载函数内部的函数重载

[英]Function overloading inside overloaded function

I am using C++14 (and pretty new to it). 我正在使用C++14 (而且还很新)。 I have 3 overloaded functions func within which another overloaded function do_something gets called depending on its parent function ( func ). 我有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();
 }

I see that the functionality within func is almost the same except which version of do_something gets called. 我看到func中的功能几乎相同,除了调用了哪个版本的do_something Is there any way I can make this generic and combine all func 's together? 有什么办法可以使这个泛型并将所有func组合在一起?

To begin with, make func a template that accepts a parameter pack. 首先,将func接受参数包的模板。 The int a argument, the call to bar and the call to foo are always there, so that's simple. int a参数,对bar的调用和对foo的调用始终存在,因此很简单。 Let's add a placeholder for do_something for now. 现在,为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;
}

You want to instantiate and invoke the above template as before: 您要像以前一样实例化并调用上述模板:

func(42);
func(42, 1.f);
func(42, 1.f, 'A');

Now let's tackle the call to do_something . 现在,让我们处理对do_something的调用。 If you simply add it in the middle of the new func template; 如果您只是将其添加到新func模板的中间, func

do_something(std::forward<Args>(other)...);

this refuses to compile for func(42) , ie, the case with only one argument. 这拒绝为func(42)编译,即只有一个参数的情况。 Hence, we need a special case for this. 因此,我们需要为此提供特殊情况。 One way to achieve this in another level of indirection for do_something : 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)...);
}

And now, the placeholder from the func function template should be: 现在, func函数模板中的占位符应为​​:

do_something_wrapper(std::forward<Args>(other)...);

The first step would be to use variadic-templates to take the part you want to forward to do_something : 第一步将使用可变参数模板来完成您要转发到do_something

template<class ... Args>
int func(int a, Args... args)
{
   bar(a);
   do_something(std::forward<Args>(args)...)
   foo();
}

But now you have lost the argument types of func. 但是现在您已经失去了func的参数类型。 So if this is a problem you will have to find a way to test them again. 因此,如果这是一个问题,您将必须找到一种方法来再次测试它们。

Although I would probably go with the answer from generic_opto_guy myself, he's right to point out that you would lose the types in your interface. 尽管我本人可能会回答generic_opto_guy的答案,但他是正确的指出您会丢失界面中的类型。 Depending on your situation, you might want to preserve this. 根据您的情况,您可能需要保留此设置。

In that case, you can easily rework it to something akin to the following: 在这种情况下,您可以轻松地将其重新整理为类似于以下内容的内容:

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); }

Note that the implementation has been adjusted to use perfect forwarding . 请注意,已对实现进行了调整,以使用完美转发 While not required in this particular case, it is often useful in forwarding situations you might encounter in the future. 尽管在这种特定情况下不是必需的,但在将来可能遇到的转发情况下,它通常很有用。

Again, unless you absolutely need to present a clear interface to client code, I would just go with the first implementation. 同样,除非您绝对需要提供一个清晰的客户端代码接口,否则我将只使用第一个实现。

The other answers are good general purpose answers to the question as asked, but if you have a few "spare" values of c available, you could write something like: 其他答案是所问问题的通用回答,但是,如果您有几个可用的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();
}

Depending on the application, this may be simpler. 根据应用程序,这可能会更简单。

Is too late to play? 玩太晚了吗?

You tagged C++14 but, if you could use C++17, you could use if constexpr so 您标记了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
 }

In C++14 you have to duplicate something somewhere. 在C ++ 14中,您必须在某处复制某些内容。

Or you write two func() s 或者您编写两个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
 }

or you add a no-argument do_something() 或添加无参数do_something()

void do_something ()
 { }

or, as suggested by lubgr, you call do_something() through a wrapper (creating a special no-argument wrapper). 或者,根据lubgr的建议,您可以通过包装器调用do_something() (创建一个特殊的无参数包装器)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM