推导函子返回类型的泛型方法
Generic way to deduce the return type of a functor?
这个问题是如何推导函子返回值的类型的后续问题?我正在用一种更抽象的方式重新表述它。
给定模板函数的伪代码
template <typename Arg, typename Fn>
auto ComputeSomething(Arg arg, Fn fn) -> decltype(<decl-expr>)
{
// do something
// ............
return fn(<ret-expr>)
}
其中<ret-expr>
是一个涉及arg
的任意表达式,<decl-expr>
应该用什么来设置ComputeSomething
的返回类型等于函子的返回类型。
函子可以是类、lambda或函数指针。
到目前为止,我找到了部分解决方案。
(a) 我的相关问题的答案由ecatmur完成。从本质上讲,它是在重复<decl-expr>
中的return语句。问题:它很容易出错,如果包含局部变量就不起作用。
(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::declval
,它应该解除默认的可构造性限制,正如在如何推导模板中函数的返回类型中所建议的那样。有人能解释一下它是怎么工作的吗?
template <typename Arg, typename Fn>
auto ComputeSomething(Arg arg, Fn fn) -> decltype(fn(std::declval<Arg>())
使用result_of。它是向后兼容的,并消除了代码中所有丑陋的declval
痛苦。如果您实际上只是转发值,那么您仍然需要记住添加右值引用限定符(&&
)。
还有一点我觉得很重要:您的函数将参数转发给另一个函数。在这种情况下,您应该始终使用右值引用来传递参数。
如果您想做的只是提高可维护性:在RETURNS
宏中,有几次尝试试图最大限度地减少返回类型声明和实际返回表达式之间的重复,但我还没有看到任何一次允许函数体包含超过实际返回语句的内容。
至于declval
是如何工作的:它依赖于编译器。它不允许出现在评估的内容中,并且它的参数可以是不完整的类型。参见20.2.4
std::declval
是一个仅声明(未定义)的函数模板。因此,它只能在未评估的上下文中使用,例如sizeof
和decltype
的自变量。它被声明为返回指定类型的右值。这允许您使用它为decltype
表达式中的函数调用制造一个伪参数。
例如
typedef decltype(fn(std::declval<Arg>())) t;
声明CCD_ 17是用类型为CCD_ 19的右值调用CCD_。这与您的案例(c)(fn(Arg())
)类似,但它不需要任何Arg
,因此它适用于没有默认构造函数的类型。
如果返回表达式使用类型为foo
的局部变量,那么无论如何构造foo
,都可以使用decltype(fn(std::declval<foo>()))
。
如果需要左值,例如命名对象或左值引用,则可以使用std::declval<foo&>()
。这允许您处理类型取决于您是否具有左值或右值的情况。
这是我自己的解决方案,我能得到的最好的
template <typename Arg, typename Fn>
typename std::result_of<Fn(Arg)>::type ComputeSomething(Arg arg, Fn fn)
要使(c)适用于任何情况,需要2个重载。第一个如(c)所示,第二个:
template <typename Arg, typename Ret>
Ret ComputeSomething(Arg arg, std::function<Ret(Arg)> fn)
此外,正如gcc错误54111所示,返回类型的推导是非常不可靠的。
(b)的一个变体,不仅使用函数指针,还应该类似
template<typename Arg, typename Ret>
Ret ComputeSomething (Arg arg, function<auto (Arg) -> Ret> f)
- QtQuick - qml:28:错误:未知方法返回类型:自定义类型
- 是否可以使用泛型枚举类型作为函数的参数?
- 对列表类中的泛型方法禁用编译器警告 2100,该泛型方法可能包含指针,也可能不包含指针
- qml 未知方法返回类型:ArchiveFile*,即使调用了 qmlRegisterUncreatableType
- 泛型方法指针.reinterpret_cast指向不同类的方法指针,这是 UB 吗?
- 如何将泛型方法传递给静态函数
- std::d eclval vs crtp,无法从不完整类型推断方法返回类型
- dlsym() 解决方法返回类型
- 如何检查模板类方法返回类型
- 覆盖方法返回类型,在C 中使用不完整的派生类
- 如何使用泛型在 C# 中将类型静态绑定在一起(如在 TypeToType <T>中)?
- 推导函子返回类型的泛型方法
- 对给定结构成员应用操作的泛型方法
- 使用基类的泛型方法指针调用派生类的方法
- 类成员方法 - 返回类型模板
- 编译器推导出了泛型lambda的类型
- C++中具有多态模板类的未知方法返回类型
- 是否可以使用Boost概念检查库验证方法返回类型
- 在没有"typedef"的情况下,如何创建用于 c# 泛型的相关类型组?
- 如何构建一个泛型方法,将不同Q_PROPERTY类型的 notifySignal 从属性 char * 名称连接到空槽