Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;11优化作为回调传递的空函数_C++_Templates_C++11_Lambda_Callback - Fatal编程技术网

C++ C++;11优化作为回调传递的空函数

C++ C++;11优化作为回调传递的空函数,c++,templates,c++11,lambda,callback,C++,Templates,C++11,Lambda,Callback,我有一个函数模板: template <class ReportFunc> void func (ReportFunc report_func) { for (/* ... */) { do_something (a, b); report_func (a, b, c); do_something_else (b, c); } } 模板 无效函数(ReportFunc report_func) { 对于(

我有一个函数模板:

template <class ReportFunc>
void func (ReportFunc report_func)
{
    for (/* ... */)
    {
         do_something (a, b);
         report_func (a, b, c);
         do_something_else (b, c);
    }
}
模板
无效函数(ReportFunc report_func)
{
对于(/*…*/)
{
做某事(a,b);
报告(a、b、c);
做点别的(b,c);
}
}
有时需要在不使用任何ReportFunc的情况下调用func(),即循环只调用do_something()和do_something_else()而不调用其他任何东西。如果我编写的f()重载不带ReportFunc参数,我将不得不复制f()的实现代码,只需删除调用report_func()的行

我有几种这类函数——有时我想用ReportFunc调用它们,有时不使用它。所以我想避免所有的代码重复。如果我传递一个空lambda或void或类似的东西,它是否应该让C++11编译器生成一个不调用任何report_func()的f()实例化?它是否像简单地删除调用report_func()的行一样快,甚至是一个空lambda也有一些编译器没有优化的开销?(在我的具体案例中,我使用GCC)


另外:如果空lambda确实这样做,并且我将函数f()的返回类型更改为ReportFunc,即它返回report_func参数,那么将返回值存储在变量中并调用它是否仍然安全?(即使它是一个空的lambda?因此调用它在理论上是可能的,它只是意味着什么都不会发生)

只要您的lambda没有通过引用捕获任何局部变量,就可以安全地返回它并稍后调用(对于空的lambda,它只是一个没有成员变量的可调用对象,因此可以安全地复制和返回)


至于调用消除,由编译器确定lambda不做任何操作并删除调用。

您可以尝试这种方法,它实现简单,无代码重复,并且减轻了在每个调用站点传递空lambda的痛苦:

struct EmptyParam
{
  void operator()(int a, int b, int c){}
};

template <class ReportFunc>
void func (ReportFunc report_func)
{
  int a = 0, b = 0, c = 0;
  for (/* ... */)
  {
    do_something (a, b);
    report_func (a, b, c);
    do_something_else (b, c);
  }
}

void func()
{
  func<EmptyParam>(EmptyParam());
}

int _tmain(int argc, _TCHAR* argv[])
{
  func([](int,int,int){});
  func();
    return 0;
}
struct EmptyParam
{
void运算符()(inta,intb,intc){}
};
模板
无效函数(ReportFunc report_func)
{
int a=0,b=0,c=0;
对于(/*…*/)
{
做某事(a,b);
报告(a、b、c);
做点别的(b,c);
}
}
void func()
{
func(EmptyParam());
}
int _tmain(int argc,_TCHAR*argv[]
{
func([](int,int,int){});
func();
返回0;
}
编辑:为了完整起见,下面的版本完全避免了对report_func的调用。对于您的特殊情况,它并不是比我提出的第一个解决方案更理想,只是另一种方式。就我个人而言,我会采用上述解决方案:

struct EmptyParam{};

template <class ReportFunc>
struct CallReportFunc
{
  static void Call(const ReportFunc & report_func, int a, int b, int c)
  {
    report_func (a, b, c);
  }
};

template <>
struct CallReportFunc<EmptyParam>
{
  static void Call(const EmptyParam &/*report_func*/, int /*a*/, int /*b*/, int /*c*/)
  {
    // do nothing
  }
};

template <class ReportFunc>
void func (ReportFunc report_func)
{
  int a =0,b =0,c=0;
  for (;true;)
  {
    CallReportFunc<ReportFunc>::Call(report_func, a, b, c);
  }
}

void func()
{
  func<EmptyParam>(EmptyParam());
}

int _tmain(int argc, _TCHAR* argv[])
{
  func([](int,int,int){});
  func();
    return 0;
}
struct EmptyParam{};
模板
结构CallReportFunc
{
静态无效调用(常量ReportFunc&report_func,int a,int b,int c)
{
报告(a、b、c);
}
};
模板
结构CallReportFunc
{
静态void调用(const EmptyParam&/*report_func*/,int/*a*/,int/*b*/,int/*c*/)
{
//无所事事
}
};
模板
无效函数(ReportFunc report_func)
{
int a=0,b=0,c=0;
因为(;真;)
{
CallReportFunc::Call(report_func,a,b,c);
}
}
void func()
{
func(EmptyParam());
}
int _tmain(int argc,_TCHAR*argv[]
{
func([](int,int,int){});
func();
返回0;
}

只需传递一个空函子

只要打开了优化,编译器就会实例化模板,内联(空)对函子的调用,因此什么也不做。它应该优化到零,不必费心元编程来尝试删除调用

我不会发誓G++会以同样的方式优化掉一个“不做任何事情”的lambda,但它应该这样做,因为类型是已知的,它的函数调用操作符是内联的,并且已知为空


使用lambda没有固有的开销,它只是用
操作符()声明对象类型并创建该类型的临时对象的语法糖。编译器前端需要做大量的工作来完成所有这些,但是一旦类型存在,优化器就应该将其视为执行相同操作的用户定义结构。出于这个原因,返回它也是安全的,它只是一个对象类型的实例,就像用户定义的函数对象一样。

将一个带有空内联
操作符()的函数对象传递给它。
。一个普通的空内联函数也应该可以工作。@n.m.如果我传递一个空lambda,它会一样快吗?我这样问是因为它使代码看起来更好:lambda是在代码中使用它的地方定义的,而不是在代码中的其他地方定义的,就像一个函子所说的那样,对于一个普通的函子来说,lambda只不过是语法上的糖而已——它们的性能应该是一样的。像往常一样,试试看:)函数将与最新版本的GCC一起工作,当函数地址是编译时常量时,它会优化间接调用,例如,您调用
func(&doNothing)
而不是
func(some_func_ptr)
其中
some_func_ptr
是一个在其他地方设置了值的变量。我刚刚使用g++进行了检查,它优化了所有内容,lambda、对象以及(使用-O3)函数。如果我只传递一个带有空运算符()的函子,会怎么样?编译器不能消除调用吗(因为操作符()无论如何都不做任何事情)?还是空的lambda?那会更糟simple@fr33domlover你的意思是
func([](){})?模板无法编译,因为它试图使用三个参数调用report_func,但不接受任何参数。在我看来,没有参数的func()重载更干净。如果你的意思是
func([](int,int,int){})然后仍然
func()
更具可读性。我指的是运算符()或lambda,参数正确,但函数体为空。我不同意,重载意味着代码重复,我已经有了,我想避免这种情况duplication@Zadirion,因此您传递它
func([](const-TypeA&,const-TypeB&,const-TypeC&){})
insteadSo-define
struct Noop{template void operator()(T&&…)const{}