如何调用函数,传递函子的返回值(可能为 void)
How to call a function, passing the return value (possibly void) of a functor?
给定一个函数,该函数调用模板化函数参数并调用另一个对返回值执行某些操作的函数:
template <typename T>
void doSomething(T &&) {
// ...
}
template <typename T_Func>
void call(T_Func &&func) {
doSomething(func());
}
如何将其扩展为与返回void
的函子一起工作?理想情况下,我想添加一个重载void doSomething() { ... }
,如果func
的返回类型为 void
,则调用该。
目前,如果func
返回void
,这只会导致error: invalid use of void expression
。
Ideone的工作示例
我认为您可以创建一个结构助手来使用重载,
运算符,或多或少如下所示:
#include <type_traits>
#include <utility>
struct my_void { };
struct my_type { };
template <class T, typename std::enable_if<std::is_void<T>::value>::type* = nullptr>
my_void operator,(T, my_type) { return {}; }
template <class T, typename std::enable_if<!std::is_void<T>::value>::type* = nullptr>
T &&operator,(T &&val, my_type) { return std::forward<T>(val); }
template <typename T>
void doSomething(T &&) {
}
template <typename T_Func>
void call(T_Func &&func) {
doSomething((func(), my_type{}));
}
int main() {
auto func1 = []() -> bool { return true; };
auto func2 = []() -> void { };
call(func1);
call(func2);
}
[现场演示]
编辑:
感谢Piotr Skotnicki和Holt(他们指出第一次重载实际上永远不会被触发,并提出了该方法的简化版本):
#include <type_traits>
#include <utility>
struct dumb_t { };
template <class T>
T &&operator,(T &&val, dumb_t) { return std::forward<T>(val); }
template <typename T>
void doSomething(T &&) {
}
template <typename T_Func>
void call(T_Func &&func) {
doSomething((func(), dumb_t{}));
}
int main() {
auto func1 = []() -> bool { return true; };
auto func2 = []() -> void { };
call(func1);
call(func2);
}
[现场演示]
doSomething()
接受参数,参数不能为空。
因此,为了使它正常工作,您还需要一个不带参数的重载doSomething()
。这将是第一步:
template <typename T>
void doSomething(T &&) {
// ...
}
void doSomething()
{
}
所以,你必须先这样做,然后才能开始。
您也可以为参数提供默认值,以防函子返回 void
; 并且仍然使用单个模板。这是另一种可能性,以下解决方案可以很容易地调整,以一种明显的方式,来处理这个问题。
这里需要发生的是返回void
的函子的call()
专用化。遗憾的是,函数不能部分专用化,因此需要一个帮助程序类:
#include <utility>
template <typename T>
void doSomething(T &&) {
// ...
}
void doSomething()
{
}
// Helper class, default implementation, functor returns a non-void value.
template<typename return_type>
class call_do_something {
public:
template<typename functor>
static void call(functor &&f)
{
doSomething(f());
}
};
// Specialization for a functor that returns a void.
//
// Trivially changed to call the template function instead, with
// a default parameter.
template<>
class call_do_something<void> {
public:
template<typename functor>
static void call(functor &&f)
{
f();
doSomething();
}
};
// The original call() function is just a wrapper, that selects
// the default or the specialized helper class.
template <typename T_Func>
void call(T_Func &&func) {
call_do_something<decltype(func())>::call(std::forward<T_Func>(func));
}
// Example:
void foobar()
{
call([] { return 1; });
call([] {});
}
您可以提供一对额外的重载帮助程序函数(在下面的示例中名为 callDispatch
)来根据需要调度调用,这消除了对部分专用化的需要,从而消除了帮助程序类的需要。它们通过对它们采用的std::function
对象使用不同的签名规范来重载(此处为实时代码):
#include <iostream>
#include <functional>
int func1()
{
return 1;
}
void func2()
{
}
template <typename T>
void doSomething(T &&)
{
std::cout << "In param version" << std::endl;
// ...
}
void doSomething()
{
std::cout << "In no-param version" << std::endl;
// ...
}
template <typename R, typename ... Args>
void callDispatch(std::function<R(Args...)> &&f)
{
doSomething(f());
}
template <typename ... Args>
void callDispatch(std::function<void(Args...)> &&f)
{
f();
doSomething();
}
template <typename T>
void call(T &&func) {
callDispatch(std::function<std::remove_reference_t<T>>(func));
}
int main() {
call(func1);
call(func2);
}
一种精简变体是给方法一个函数作为参数。然后,计算方法中的表达式,看看是否执行了任何操作。一般来说,这通常是不好的做法,因为您通常可以推断它如何返回东西以及何时需要它。
- 从python中调用C++函数并获取返回值
- 为什么模板类中的对象不能返回值
- 返回值优化:显式移动还是隐式
- lock_guard是否保护返回值
- 当我使用 void 函数的返回值(通过强制转换函数指针)时,究竟会发生什么?
- 结构新手,我对如何从 void 函数中返回值并将其放入另一个函数感到困惑
- 将 void 函数更改为返回值函数
- C++ - 在线程中使用时,将函数的返回值声明为 void/void* 之间有什么区别吗?
- 如何调用函数,传递函子的返回值(可能为 void)
- 缺少返回语句的非 void 函数的返回值是多少?
- C++:从void函数返回void函数的返回值
- 为什么要编译这个C++代码段(非void函数不返回值)
- C++ "const void" 作为返回值比 "void" 更正确?
- 使用引用的Void函数与在C++中返回值的函数相比
- 前面带有 * 且返回值为 void 的函数声明
- 不返回值,来自具有非void返回类型的函数
- 处理返回void的方法和返回值的方法
- 是否有可能避免有关 void 函数返回值的外部引用换行错误
- 覆盖 C++ 中的非 void 函数,supers 返回值返回到何处
- 外部参照换行错误:'void'函数返回值