带有默认返回值的C++弱函子
C++ weak functor with default return value
在这个社区的帮助下,我有了以下模板方法。。。
// void return
template<typename R, typename = typename std::enable_if<std::is_void<R>::value, R>::type,
typename F, typename T, typename... A>
static std::function<R()> Weak(F func, const std::shared_ptr<T>&& obj, A&&... args)
{
return std::bind(Wrapper<R>(), std::weak_ptr<T>(obj),
std::function<R()>(std::bind(func, obj.get(), args...)));
}
// non void return
template<typename R, R D = R(), typename = typename std::enable_if<std::is_void<R>::value == false, R>::type,
typename F, typename T, typename... A>
static std::function<R()> Weak(F func, const std::shared_ptr<T>&& obj, A&&... args)
{
return std::bind(Wrapper<R>(), std::weak_ptr<T>(obj),
std::function<R()>(std::bind(func, obj.get(), args...)), D);
}
其中,Wrapper是一个模板类,用于测试弱指针,并在指定的默认值过期时返回该值。用法示例如下。。。
(a) Bind::Weak<void>(func, obj, args...)
(b) Bind::Weak<bool>(func, obj, args...) // default bool is "false"
(c) Bind::Weak<bool, true>(func, obj, args...)
(b) Bind::Weak<int>(func, obj, args...) // default int is "0"
(c) Bind::Weak<int, 42>(func, obj, args...)
是否可以支持以下用法?
(a) Bind::Weak<void>(func, obj, args...)
(b) Bind::Weak<true>(func, obj, args...)
(c) Bind::Weak<42>(func, obj, args...)
[编辑]下面Oktalist的回复给了我以下想法。。。
// weak from shared - void return
template<typename F, typename O, typename... A>
static std::function<void()> Weak(F func, const std::shared_ptr<O>&& obj, A&&... args)
{
return std::bind(Wrapper<void>(), std::weak_ptr<O>(obj), std::function<void()>(std::bind(func, obj.get(), std::forward<A>(args)...)));
}
// weak from shared - non-void return
template<typename F, typename R = typename std::enable_if<std::is_void<F>::value == false, F>::type, typename O, typename... A>
static std::function<R()> Weak(R&& val, F func, const std::shared_ptr<O>&& obj, A&&... args)
{
return std::bind(Wrapper<R>(), std::weak_ptr<O>(obj), std::function<R()>(std::bind(func, obj.get(), std::forward<A>(args)...)), val);
}
它给出了这种用法。。。
(a) Bind::Weak(func, obj, args...)
(b) Bind::Weak(true, func, obj, args...)
(c) Bind::Weak(42, func, obj, args...)
我能想到的唯一可能帮助您解决这个问题的方法是为您可能支持的每种非类型模板参数重载您的非void版本的弱。在您的示例中,这是一个bool和一个int。
这不是你的代码,因为它被简化了,但希望能传达这样的想法:
// accepts a type. using enable_if you'd do something like this
// to catch all the non-void types that don't have a default value.
template <class R, ...enable_if to only deal with non-void... >
R Get( R r )
{
return r;
}
// this for if the user wants to put an actual value as a parameter
// to be the default rather than just 'int'
template <int R>
decltype(R) Get( decltype(R) r = R )
{
return r;
}
// ... and do the previous one for each specific type which can have a default
基本上,问题是像"42"answers"false"这样的特定值不会绑定到"typename"。因此,您需要函数的专用模板来接受这些值,然后您可以在需要使用decltype((时获得该值的类型。这将消除有时需要一个参数(即:Get<int>(而有时需要两个参数(例如:Get&llt;int,42>以指定默认值(的需要。
对于您的示例来说,另一个似乎可以接受但在"现实世界"中可能不可接受的限制是对模板参数本身的限制。你将无法执行弱<foo>,其中foo是一个类的实例。
我在同一个问题上花了一些时间,并提出了以下问题:
#include <functional>
#include <memory>
template <typename F, typename T>
struct Invoker {
typedef std::weak_ptr<T> P;
Invoker(F func, P ptr)
: func_(func),
ptr_(ptr) {
}
template <typename... Args>
typename std::result_of<F(Args...)>::type operator()(Args&&... args) {
typedef typename std::result_of<F(Args...)>::type R;
if (ptr_.lock())
return func_(std::forward<Args>(args)...);
return R();
}
private:
F func_;
P ptr_;
};
template <typename F, typename T, typename... Args>
struct _Bind_helper {
typedef Invoker<decltype( std::bind(std::declval<F>(), std::declval<Args>()...) ), T> InvokerType;
};
template <typename F, typename T, typename... Args>
typename _Bind_helper<F, T, Args...>::InvokerType
weak_bind(std::weak_ptr<T> ptr, F func, Args&&... args) {
typedef typename _Bind_helper<F, T, Args...>::InvokerType R;
return R(std::bind(std::forward<F>(func), std::forward<Args>(args)...), ptr);
}
默认结果值有明显的限制,但它似乎在大多数情况下都有效:(
是的,您可以使用函数特性来推导可调用类型F
的返回类型。
从模板参数列表中删除typename R
,将typename F
移动到模板参数列表的开头,并用typename function_traits<F>::return_type
替换所有出现的R
。我们可以使用template using
声明来帮助我们:
template <typename F>
using Ret = typename function_traits<F>::return_type;
template <typename T>
using EnableIfVoid = typename std::enable_if<std::is_void<T>::value, T>::type;
template <typename T>
using EnableIfNotVoid = typename std::enable_if<! std::is_void<T>::value, T>::type;
// void return
template<typename F, typename = EnableIfVoid<Ret<F>>, typename T, typename... A>
static std::function<void()> Weak(F func, const std::shared_ptr<T>& obj, A&&... args)
{
return std::bind(Wrapper<void>(), std::weak_ptr<T>(obj),
std::function<void()>(std::bind(func, obj.get(),
std::forward<Args>(args)...)));
}
// non void return with explicit default
template<typename F, typename = EnableIfNotVoid<Ret<F>>, typename T, typename... A>
static std::function<Ret<F>()> Weak(Ret<F> d, F func, const std::shared_ptr<T>& obj, A&&... args)
{
return std::bind(Wrapper<Ret<F>>(), std::weak_ptr<T>(obj),
std::function<Ret<F>()>(std::bind(func, obj.get(),
std::forward<Args>(args)...)), d);
}
// non void return with implicit default
template<typename F, typename = EnableIfNotVoid<Ret<F>>, typename T, typename... A>
static std::function<Ret<F>()> Weak(F func, const std::shared_ptr<T>& obj, A&&... args)
{
return Weak(Ret<F>(), func, obj, std::forward<Args>(args)...);
}
我必须将D
参数设置为函数参数,而不是模板参数,否则您将被迫编写Bind::Weak<decltype(f), 42>(f, obj)
。
(a) Bind::Weak(func, obj, args...)
(b) Bind::Weak(true, func, obj, args...)
(c) Bind::Weak(42, func, obj, args...)
[我觉得你应该可以做到这一点,而不必打两次bind
,但我对你想做什么还不够了解。]
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- 如何使用默认参数等选择模板专业化
- 具有默认模板参数的多态类的模板推导失败
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 当函数模板参数是具有默认参数的类模板时,函数模板参数的推导如何执行
- 初始化具有非默认构造函数的std::数组项的更好方法
- 何时提供默认参数作为模板参数
- 是默认情况下分配给char数组常量的值
- 具有默认值的引用获取函数
- 具有默认模板类型的默认构造函数的类型推导
- 当给定默认值时,为什么此模板参数推导失败
- 修改 VS Code 中的默认C++代码段
- 声明默认的模板化函数
- 将const引用参数初始化为默认参数会导致悬空引用吗
- 如何使用非默认构造函数实例化模板化类
- 如何修复带有 clang 的参数'args'缺少默认参数的问题?
- 从具有默认值的部分指定模板类继承时发生SWIG错误,具有不带默认值的正向声明
- 为什么大多数 pair 实现默认不使用压缩(空基优化)?
- 格式化浮点值:返回默认值
- 对于MacOS上的G++,如何添加默认的include目录/usr/local/include和默认的库搜索路径/usr