【发布时间】:2017-10-04 12:26:40
【问题描述】:
我偶然发现了我的代码中的一个错误,我将其追溯到std::bind 的参数“...are never passed by reference unless wrapped in std::ref or std::cref”。
我有什么
我有一个看起来像这样的函数模板(去掉了不相关的部分):
template<typename F, typename ... Args>
auto eval(F&& _f, Args&&... _args)
{
using ret_t = typename std::result_of<F&&(Args&&...)>::type;
std::function<ret_t()> func(std::bind(std::forward<F>(_f), std::forward<Args>(_args)...)));
// Etc.
}
到目前为止一切都很好,但是如果函数_f 将引用作为参数,因为除非包含在std::ref 或std::cref 中,否则参数会被复制或移动,这会失败。
我想要什么
一种将参数作为对_f 的引用传递的方法,同时尽可能保持完美转发。我非常希望通过在原点将std::ref 包装在_args 中来避免传递每个_args。相反,我希望在 eval() 中自动找出引用。
我尝试过的
当binding _args 似乎有效时,使用std::ref 而不是std::forward:
template<typename F, typename ... Args>
auto eval(F&& _f, Args&&... _args)
{
using ret_t = typename std::result_of<F&&(Args&&...)>::type;
// Replace std::forward<Args>() with std::ref()
std::function<ret_t()> func(std::bind(std::forward<F>(_f), std::ref(_args)...)));
// Etc.
}
但我不知道右值引用的行为如何。始终使用std::ref 是否安全?是不是矫枉过正?我还有完美的转发吗?问题比比皆是。
我也考虑过用通用 lambda 替换 std::bind,但我不确定如何捕获参数以实现完美转发。
任何见解都将不胜感激。
【问题讨论】:
-
如果 arg 是一个右值,那么你会遇到问题,如果你引用一个引用,并在
eval之外传递func。因此,您想改用std::ref(std::forward<Args>(_args))。如果 arg 是右值,这将使编译器失败。除此之外,我认为这个解决方案很好(如果你不将func传递给函数之外,那么你可以使用当前的解决方案) -
谢谢,这很有用。如果我必须在
eval()之外通过func,你知道我能做什么吗? -
那你需要申请copy:在这种情况下不要使用
std::ref。我认为这可以通过一些模板专业化来完成。 -
或仅使用函数重载:创建一个类似
std::ref的函数,它也适用于右值引用(在左值引用的情况下,它应该返回std::reference_wrapper,在右值引用的情况下,它应该返回右值引用)。
标签: c++ c++14 variadic-templates perfect-forwarding stdbind