我只是在看一些代码与下面的粗略大纲。
#include <iostream>
template<typename T, typename F>
decltype(auto) do_something(T&& object, F f) {
return f(std::forward<T>(object));
}
struct object {
int x;
int& ref() { return x; }
int const& ref() const { return x; }
};
struct f {
template<typename T>
decltype(auto) operator()(T&& x) {
return x.ref();
}
};
int main(int argc, char** argv) {
auto & x = do_something(object{}, f{});
return 0;
}
如果我这样打电话
auto& do_something(object{}, f{);
围绕这一点的一些问题是,如果f
返回一个引用,并且f
通过移动语义取得object
的所有权,我们是否会遇到生存期问题?
通过decltype(auto)
返回的潜在问题是什么?
还是这样更好
#include <iostream>
#include <type_traits>
struct object {
int x{};
int const& ref() const noexcept { return x; }
int& ref() noexcept { return x; }
};
struct functor {
template<typename T>
decltype(auto) operator()(T&& arg) {
return arg.ref();
}
};
template<typename T, typename F>
decltype(auto) apply(T&& o, F f) {
if constexpr(std::is_lvalue_reference_v<T>) {
return f(std::forward<T>(o));
}else {
auto result = f(std::forward<T>(o));
return result;
}
}
1条答案
按热度按时间xfb7svmp1#
f
通过移动语义取得对象的所有权如果
f
是一个函数,那么即使没有 Package 器,它也不可能从一开始就返回对它的有效引用。但是您的代码并不拥有它所赋予的对象的所有权,所以这是正常的。
还有一种不同的、相当模糊的失败场景:
f
是一个函子,它把参数移到它的成员变量中,然后返回一个对它的引用,那么在f
死了之后,你会得到一个悬空引用:这里,
A{}(object{}).foo()
是法律的的,但是do_something(object{}, A{}).foo()
是UB。解决方案是使用
F &&f
(无论如何,这是一个好主意,以避免复制)。在调用它时,您还应该使用std::forward<F>(f)
: