Совершенные переадресации вызываемых объектов в функциях более высокого порядка
Я писал такие функции более высокого порядка:
template<typename F, typename... Args>
void doStuff(F f, Args&&... args)
{
// ...
f(std::forward<Args>(args)...);
// ...
}
Или замените F f
на F&& f
.
Но после того, как я узнал о ref-qualifiers (ouch), все усложнилось. Представьте себе класс функтора:
struct Foo {
void operator()(...) &;
void operator()(...) &&;
};
Тогда мои предыдущие реализации doStuff
будут когда-либо вызывать метод &
, так как параметры всегда lvalues.
Я думаю, что способ решить это - реализовать doStuff
следующим образом:
template<typename F, typename... Args>
void doStuff(F&& f, Args&&... args)
{
// ...
std::forward<F>(f)(std::forward<Args>(args)...);
// ...
}
Это также означает, что std::result_of
возможно реализовано. Я хочу знать, есть ли какой-то недостаток этой реализации, т.е. Следует ли мне заменять все мои HOF-реализации?
Ответы
Ответ 1
std::forward
- это условное значение r-значения, и точка, как обычно, крадет кишки из умирающих объектов. В этом отношении нет разницы между functors
и другими объектами. Нижняя сторона такая же, как при любом использовании std::forward
; если вы не готовы украсть эти кишки, вы не должны.
#include <iostream>
#include <vector>
struct Foo {
std::vector<int> vec = {1,2,3};
std::vector<int>& operator()(...) & {
return vec;
}
std::vector<int> operator()(...) && {
return std::move(vec);
// Clearly, don't rely on 'vec' here...
}
};
Foo getFoo(){
return {};
}
int main() {
auto foo = getFoo();
auto vec1=foo();
auto vec2=getFoo()();
}
Ясно, что не делайте такие вещи:
auto vec3 = std::move(foo)();
vec4 = foo();
по тем же причинам.