14

这个问题是如何推断函子返回值的类型的后续问题? 我正在以更抽象的方式重新制定它。

给定模板函数的伪代码

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

where<ret-expr>是一个包含 的任意表达式arg,我应该用什么<decl-expr>来设置返回类型ComputeSomething等于函子的返回类型。

仿函数可以是类、lambda 或函数指针。

到目前为止我找到的部分解决方案。

(a) ecatmur 完成的我的链接问题的答案。本质上,它是在重复 return 语句<decl-expr>。问题:它很容易出错,如果包含局部变量则不起作用。

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

template <typename Arg, typename Ret>
Ret ComputeSomething(Arg arg, Ret(*fn)(Arg))

(c) 它假设函子的参数是类型的Arg(一般情况下可能不成立)并且要求Arg是可默认构造的

template <typename Arg, typename Fn>
auto ComputeSomething(Arg arg, Fn fn) -> decltype(fn(Arg())

(d) 使用std::declvalwhich 应该解除默认可构造的限制,如如何在 template 中推断函数的返回类型中所建议的那样。有人可以解释它是如何工作的吗?

template <typename Arg, typename Fn>
auto ComputeSomething(Arg arg, Fn fn) -> decltype(fn(std::declval<Arg>())
4

5 回答 5

12

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

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

如果您要做的只是提高可维护性:RETURNS围绕宏进行了多次尝试,以尽量减少返回类型声明和实际返回表达式之间的重复,但我还没有看到任何允许包含的函数体超过实际的返回语句。

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

于 2012-08-20T07:23:52.987 回答
11

std::declval是一个仅声明(未定义)的函数模板。因此,它只能用于未评估的上下文中,例如 和 的sizeof论点decltype。它被声明为返回指定类型的右值。decltype这允许您使用它来为表达式中的函数调用制造一个虚拟参数。

例如

typedef decltype(fn(std::declval<Arg>())) t;

声明为使用 type的右值t调用的结果的类型。这类似于您的情况 (c) ( ),但它不需要任何,因此它适用于没有默认构造函数的类型。fnArgfn(Arg())Arg

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

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

于 2012-08-20T10:36:59.070 回答
5

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

template <typename Arg, typename Fn>
typename std::result_of<Fn(Arg)>::type ComputeSomething(Arg arg, Fn fn)
于 2012-08-20T12:01:03.883 回答
3

要使 (c) 适用于任何东西,您需要 2 个重载。第 1 次如 (c) 所示,第 2 次:

template <typename Arg, typename Ret>
Ret ComputeSomething(Arg arg, std::function<Ret(Arg)> fn)

此外,正如gcc 错误 54111所示 - 返回类型的推断非常不可靠。

于 2012-08-20T07:29:03.220 回答
2

(b) 的变体不仅与函数指针一起工作,应该类似于

template<typename Arg, typename Ret>
Ret ComputeSomething (Arg arg, function<auto (Arg) -> Ret> f)
于 2012-08-20T07:24:12.787 回答