最近我尝试通过std::unique_ptr
重新发明范围保护(注意:删除有成员typedef pointer
- 是std::unique_ptr
)的特殊处理案例:
#include <type_traits>
#include <utility>
#include <memory>
#include <iostream>
#include <cstdlib>
#include <cassert>
namespace
{
template< typename lambda >
auto
make_scope_guard(lambda && _lambda)
{
struct lambda_caller
{
using pointer = std::decay_t< lambda >;
void
operator () (lambda & l) const noexcept
{
std::forward< lambda >(l)();
}
};
return std::unique_ptr< std::decay_t< lambda >, lambda_caller >(std::forward< lambda >(_lambda));
}
}
int
main()
{
std::cout << 1 << std::endl;
{
std::cout << 2 << std::endl;
[[gnu::unused]] auto && guard_ = make_scope_guard([&] { std::cout << __PRETTY_FUNCTION__ << std::endl; });
std::cout << 3 << std::endl;
}
std::cout << 5 << std::endl;
return EXIT_SUCCESS;
}
这种方法适用于传递给void f() { std::cout << 4 << std::endl; }
的自由函数make_scope_guard
的简单指针,但不适用于传递给make_scope_guard
的任何lambda。
这是由于... = pointer()
定义中的std::unique_ptr
丰富(函数默认参数,默认数据成员等),但我无法找到 DefaultConstructible 要求pointer
进入article。
是强制性的,pointer
是否应符合std::is_default_constructible
要求?
使用不太旧的libc++
对libstdc++
和clang++ -std=gnu++1z
进行了测试。
似乎,lambdas应该有语言扩展:如果auto l = [/* possible capture list */] (Args...) { /* code */; };
那么using L = decltype(l);
相当于某些struct L { constexpr void operator () (Args...) const noexcept { ; } };
的{{1}},那么它不是吗?
其他
将以下 DefaultConstructible 类的实例Args...
提供给D{}
,需要在上下文make_scope_guard(D{})
中取消注释已注释掉的代码,其中if (p) { ...
属于p
类型:
D
答案 0 :(得分:4)
mysite.com/profile/
仍是指针。你不能把一个lambda钉进去。来自[unique.ptr]:
唯一指针是拥有另一个对象并通过指针管理该另一个对象的对象。 更准确地说,唯一指针是一个对象,它将指针存储到第二个对象p并将被处置 p当你自己被摧毁时
[...]
此外, u 可以根据请求将所有权转移到另一个唯一指针 u2 。完成后 这样的转移,以下后置条件成立:[...] u.p 等于
unique_ptr
lambda不是指针。 lambda不能等于nullptr
。
那就是说,你已经在制作自己的本地结构了,为什么不使用那个来做RAII范围而不是推迟到nullptr
呢?这似乎是一个hack充其量,并需要更多的代码来启动。你可以改为:
unique_ptr
如果您需要支持template< typename lambda >
auto
make_scope_guard(lambda && _lambda)
{
struct lambda_caller
{
lambda _lambda;
~lambda_caller()
{
_lambda();
}
};
return lambda_caller{std::forward<lambda>(_lambda)};
}
,可以将release
包裹在_lambda
内,以便boost::optional
成为:
lambda_caller