给定一个调用模板化函数参数的函数,并调用另一个函数来执行返回值:
template <typename T>
void doSomething(T &&) {
// ...
}
template <typename T_Func>
void call(T_Func &&func) {
doSomething(func());
}
如何将其扩展为使用返回void
的仿函数?理想情况下,如果void doSomething() { ... }
的返回类型为func
,我想添加一个被调用的重载void
。
目前,如果error: invalid use of void expression
返回func
,这只会产生void
。
答案 0 :(得分:3)
我认为你可以创建一个struct helper来使用重载的,
运算符或多或少这样:
#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);
}
答案 1 :(得分:1)
doSomething()
接受一个参数,参数不能为空。
因此,为了使其工作,您还需要一个不带参数的重载doSomething()
。这将是第一步:
template <typename T>
void doSomething(T &&) {
// ...
}
void doSomething()
{
}
所以,在你开始行动之前,你必须先做这件事。
如果仿函数返回void
,您也可能希望为参数提供默认值;并且仍然使用单个模板。这是另一种可能性,并且可以通过显而易见的方式轻松调整以下解决方案来处理。
这里需要做的是call()
的特殊化,用于返回void
的仿函数。不幸的是,函数不能部分专门化,因此需要一个辅助类:
#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([] {});
}
答案 2 :(得分:0)
你可以提供一对额外的重载辅助函数(在我下面的例子中命名为callDispatch
)来根据需要调度调用,这样就不需要部分特化,因此不需要辅助类。他们使用std::function
对象的不同签名规范(实时代码here)来重载它们:
#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);
}
答案 3 :(得分:-1)
一个精益变体将是给该方法一个函数作为参数。然后,您评估方法内的表达式,看看是否做了什么。一般来说,这通常是不好的做法,因为你通常可以推断它是如何返回东西以及何时需要它。