我想一般性地“挑选”函数调用,以便以后执行它们。这些函数的返回类型始终为void
(暂时)。像这样:
template<typename F, typename... Args>
std::function<void()>
pickle(F function, Args&&... args) {
return std::bind(F, args...);
}
问题是,如果args
包含const引用,std::bind
会尝试复制构造值,如果类型缺少复制构造函数,则该值并不总是需要甚至有效。如何以对左值引用使用std::ref
和为左值引用使用普通std::forward
的方式转发参数?
#include <functional>
class NonCopyable {
public:
NonCopyable() {}
NonCopyable(const NonCopyable&) = delete;
};
template<typename F, typename... Args>
std::function<void()>
pickle(F function, Args&&... args)
{
return std::bind(function, std::forward<Args>(args)...);
}
int main()
{
NonCopyable obj;
auto f = pickle(
[](const NonCopyable&) {},
obj
);
return 0;
}
上面的代码片段无法编译,抱怨已删除的拷贝构造函数。 (我在这里使用过,因为有人提出了这个建议,但似乎已经删除了他们的答案)。
答案 0 :(得分:8)
超载,是的。
// also does the correct thing for `T const`
template<class T>
std::reference_wrapper<T> maybe_ref(T& v, int){ return std::ref(v); }
// just forward rvalues along
template<class T>
T&& maybe_ref(T&& v, long){ return std::forward<T>(v); }
template<typename F, typename... Args>
std::function<void()>
pickle(F function, Args&&... args) {
return std::bind(function, maybe_ref(std::forward<Args>(args), 0)...);
}
int
/ long
参数和0
参数消除了对于发现重载不明确的编译器的左值情况,否则不会造成任何伤害。
答案 1 :(得分:0)
这有点难看(过度使用enable_if
),但它有效:
template<typename T> typename std::enable_if<
!std::is_lvalue_reference<T>::value, T &&>::type
forward_as_ref(typename std::remove_reference<T>::type &t) {
return static_cast<T &&>(t);
}
template<typename T> typename std::enable_if<
!std::is_lvalue_reference<T>::value, T &&>::type
forward_as_ref(typename std::remove_reference<T>::type &&t) {
return t;
}
template<typename T> typename std::enable_if<
std::is_lvalue_reference<T>::value,
std::reference_wrapper<typename std::remove_reference<T>::type>>::type
forward_as_ref(T t) {
return t;
}
这是使用类模板特化的版本:
template<typename T> struct forward_as_ref_type {
typedef T &&type;
};
template<typename T> struct forward_as_ref_type<T &> {
typedef std::reference_wrapper<T> type;
};
template<typename T> typename forward_as_ref_type<T>::type forward_as_ref(
typename std::remove_reference<T>::type &t) {
return static_cast<typename forward_as_ref_type<T>::type>(t);
}
template<typename T> T &&forward_as_ref(
typename std::remove_reference<T>::type &&t) {
return t;
}