推断出仿函数的返回类型的通用方法?

And*_*rey 13 c++ lambda templates c++11

这个问题是如何推断出仿函数的返回值类型的后续行动 我正在以更抽象的方式重新制定它.

给定模板函数的伪代码

template <typename Arg, typename Fn>
auto ComputeSomething(Arg arg, Fn fn) -> decltype(<decl-expr>)
{
// do something
// ............
return fn(<ret-expr>)
}
Run Code Online (Sandbox Code Playgroud)

where <ret-expr>是一个涉及的任意表达式,arg我将使用什么<decl-expr>来设置返回类型ComputeSomething等于函子的返回类型.

仿函数可以是类,lambda或函数指针.

到目前为止我发现的部分解决方案.

(a)ecatmur所做的相关问题的答案.从本质上讲,它重复了返回语句<decl-expr>.问题:它容易出错,如果包含局部变量则无法工作.

(b)它仅适用于函数指针

template <typename Arg, typename Ret>
Ret ComputeSomething(Arg arg, Ret(*fn)(Arg))
Run Code Online (Sandbox Code Playgroud)

(c)它假定仿函数的参数是类型的Arg(一般可能不成立)并且需要Arg默认构造

template <typename Arg, typename Fn>
auto ComputeSomething(Arg arg, Fn fn) -> decltype(fn(Arg())
Run Code Online (Sandbox Code Playgroud)

(d)使用std::declval哪个应该解除默认构造限制,如在模板中推导函数的返回类型所建议的那样.谁有人解释它是如何工作的?

template <typename Arg, typename Fn>
auto ComputeSomething(Arg arg, Fn fn) -> decltype(fn(std::declval<Arg>())
Run Code Online (Sandbox Code Playgroud)

pmr*_*pmr 11

使用result_of.它向后兼容,并declval消除了代码中的所有丑陋痛苦.&&如果实际上只是转发值,您仍需要记住添加右值引用限定符().

我发现其他重要的东西:你的函数将参数转发给另一个函数.在这种情况下,您应该始终使用rvalue引用来传递参数.

如果您要做的就是提高可维护性:在一个RETURNS宏周围有几次尝试尝试最小化返回类型声明和实际返回表达式之间的重复,但我还没有看到任何允许包含的函数体超过实际的退货声明.

至于如何declval工作:它依赖于编译器.不允许在评估的内容中出现,并且其参数可以是不完整的类型.见20.2.4


Ant*_*ams 11

std::declval是一个仅声明(未定义)的函数模板.因此,它可以仅在未计算的上下文中使用,如参数sizeofdecltype.声明它返回指定类型的右值.这允许您使用它为decltype表达式中的函数调用生成伪参数.

例如

typedef decltype(fn(std::declval<Arg>())) t;
Run Code Online (Sandbox Code Playgroud)

声明tfn使用rvalue类型调用的结果的类型Arg.这类似于你的case(c)(fn(Arg())),但它不需要任何东西Arg,所以它适用于没有默认构造函数的类型.

如果返回表达式使用类型的局部变量foo,那么decltype(fn(std::declval<foo>()))无论您如何构造a,都可以再次使用foo.

如果您需要左值,例如命名对象或左值引用,则可以使用std::declval<foo&>().这允许您处理类型取决于您是否具有左值或右值的情况.

  • `std :: declval <Arg&>()`也是值得考虑的,特别是考虑到你提到了一个局部变量. (2认同)

And*_*rey 5

这是我自己的解决方案,我能得到的最好的解决方案

template <typename Arg, typename Fn>
typename std::result_of<Fn(Arg)>::type ComputeSomething(Arg arg, Fn fn)
Run Code Online (Sandbox Code Playgroud)