template <typename T>
void myFunction(..., T && callback) {
...
callback(...);
...
}
使用T &&
比使用T&
或const T&
更好吗?
甚至可以简单地T
按值传递而不是按引用传递。
函数或lambda是否具有左值和右值的概念?我可以std::move
使用函数/ lambda吗?
const
中的const T&
是否强制执行该函数无法修改其闭包?
答案 0 :(得分:5)
采用转发引用可以有所作为,但是您必须正确调用回调才能看到它。对于函数和lambda,它们是右值还是左值都没有关系,但是如果您有函子,则可以有所作为
template <typename T>
void myFunction(..., T && callback) {
callback(...);
}
获取转发引用,然后将回调作为左值调用。如果函数对象作为右值传递,并且其调用运算符定义为
,则可能会出错operator()(...) && { ... }
因为只能在右值上调用。为了使您的函数正常工作,您需要将函数名称包装在std::forward
中,以便在与传递给函数的值表达式类别中进行调用。看起来像
template <typename T>
void myFunction(..., T && callback) {
std::forward<T>(callback)(...);
// you should only call this once since callback could move some state into its return value making UB to call it again
}
因此,如果要获取右值和左值,并以右值或左值调用运算符,则应使用上述方法,因为它就像在myFunction
的调用站点中进行调用
答案 1 :(得分:1)
使用T &&比使用T&或const T&更好吗?
通用引用可以实现完美的转发,因此在通用模板功能中通常更可取。
或者甚至简单地用T传递值,而不是引用传递。
当您希望拥有所有权时,这通常是更可取的。
函数或lambda是否具有左值和右值的概念?
是的。每个值表达式都有一个值类别。
我可以std :: move函数/ lambdas吗?
是的。您几乎可以std::move
进行任何操作。
另一件事是是否从std::move
移出对象。还有另一个问题是对象是否可以移动。 Lambda是可移动的,除非它们包含不可移动的捕获。
答案 2 :(得分:1)
在OP的示例中:
template <typename T>
void myFunction(..., T && callback) {
...
...
}
通过T&&
将使您两全其美。如果传递一个r值引用,则模板将使用一个r值引用来解析函数,但是如果传递一个l值引用,则该函数将解析为一个l值。传递callback
时,请记住要使用std::forward
来保留l / r值。
这仅在将T模板化的情况下才有效,而在使用std :: function之类的情况下则不会。
那么我们在非模板示例中要传递什么。首先要确定的是在函数退出后是否可以调用callback
。如果仅在myFunc
范围内调用回调,则最好使用l值引用,因为您可以直接调用该引用。
但是,如果将在callback
的范围之后调用myFunc
,则使用r值将允许您move
callback
。这样可以节省您的副本,但会迫使您保证在传递到myFunc
之后,回调不能在其他任何地方使用。
答案 3 :(得分:0)
在C ++函数中(不要与@app.route('/method_a', methods=['GET'])
def method_a():
x = request.cookies.get('xcookie', 0)
x = x + 1
response = jsonify({'mesaage': 'value of x incremented by 1 is: '+str(x)})
response.set_cookie('xcookie', x)
return response
混淆)实际上只是指针。您可以移动指针,尽管它与复制指针相同。
内部的Lambda或多或少是常规的std::function
(或struct
,它们是相同的),它们实现了class
并可能存储某些状态(如果您的Lambda捕获了状态) )。因此operator()
的功能与常规结构的功能相同。
类似地,可能会有move
个lambda(因为它们的状态中只有可移动的值)。因此,有时候,如果您想接受此类lambda,则需要经过move-only
。
但是,在某些情况下,您需要一个副本(例如,如果要在线程中执行函数)。
答案 4 :(得分:0)
您可能想要选择T
(带有可选的std::ref
)或T&&
并坚持使用其中一个。
T const&
不会修改myFunction
,则 callback
是有用的。如果callback
可能是有状态的,则不起作用。当然,如果将callback
的{{1}}标记为operator()
(或const
是非callback
lambda),则mutable
将不会t修改myFunction
。本质上,呼叫callback
的人都可以为自己提供这种一致性保证。
myFunction
引入有状态函子,则 T&
可以使用。缺点是myFunction
无法绑定到右值(例如T&
)。
myFunction([&](Type arg){ /* whatever */ })
对有状态函子和无状态函子均适用,并且适用于右值(例如lambdas)和左值。如果呼叫T
的某人希望在myFunction
之外可以观察到callback
的状态变化(例如myFunction
不仅仅是callback
),他们可以使用operator()
。这就是C ++标准库所附带的。
std::ref
类似地是通用的(它可以处理右值和/或有状态函子),但是它不需要T&&
就可以从外部看到对std::ref
的更改。 callback
。