移动包含 lambda 的元组
Move tuple containing lambda
我正在尝试实施通用 RAII 清理。这看起来像是在工作,直到我尝试使用移动构造函数:
#include <functional>
#include <tuple>
#include <utility>
template <typename R, typename D>
class Cleaner {
public:
Cleaner() = default;
Cleaner(R r, D d = {}) : data(std::move(d), std::move(r)), owns(true) {
}
~Cleaner() {
if (!owns) return;
std::apply(
[](auto&&... args){
std::invoke(std::forward<decltype(args)>(args)...);
},
std::move(data)
);
}
Cleaner(Cleaner&& other) noexcept {
swap(*this, other);
}
Cleaner& operator=(Cleaner&& other) noexcept {
swap(*this, other);
return *this;
}
void release() { owns = false; }
R& get() { return std::get<1>(data); }
R const& get() const { return std::get<1>(data); }
friend void swap(Cleaner& a, Cleaner& b) noexcept {
using std::swap;
swap(a.data, b.data);
swap(a.owns, b.owns);
}
private:
std::tuple<D, R> data;
bool owns = false;
};
#include <iostream>
int main() {
auto c = Cleaner(0, [](int){ std::cout << "clean\n"; });
auto a(std::move(c)); // <- this fails to compile
}
(编译报错信息太长复制到这里,不过你可以在这里看到:https://godbolt.org/z/5fqz5qTxT)
消息开头为:
source>: In instantiation of 'Cleaner<R, D>::Cleaner(Cleaner<R, D>&&) [with R = int; D = main()::<lambda(int)>]':
<source>:48:24: required from here
<source>:20:37: error: no matching function for call to 'std::tuple<main()::<lambda(int)>, int>::tuple()'
20 | Cleaner(Cleaner&& other) noexcept {
| ^
In file included from /opt/compiler-explorer/gcc-trunk-20220208/include/c++/12.0.1/functional:54,
from <source>:1:
/opt/compiler-explorer/gcc-trunk-20220208/include/c++/12.0.1/tuple:1259:9: note: candidate: 'template<class _Alloc, class _U1, class _U2, typename std::enable_if<__is_explicitly_constructible<_U1, _U2>(), bool>::type <anonymous> > std::tuple<_T1, _T2>::tuple(std::allocator_arg_t, const _Alloc&, std::pair<_U1, _U2>&&) [with _U1 = _Alloc; _U2 = _U1; typename std::enable_if<std::_TupleConstraints<true, _T1, _T2>::__is_explicitly_constructible<_U1, _U2>(), bool>::type <anonymous> = _U2; _T1 = main()::<lambda(int)>; _T2 = int]'
1259 | tuple(allocator_arg_t __tag, const _Alloc& __a, pair<_U1, _U2>&& __in)
| ^~~~~
[...]
有人可以帮助我了解问题所在以便我解决吗?
你的问题是 lambda 不是默认可构造的(non-capturing 是自 C++20 起)。
您可以将构造函数更改为:
Cleaner(Cleaner&& other) noexcept :
data(std::move(other.data)),
owns(other.owns)
{
other.owns = false;
}
我正在尝试实施通用 RAII 清理。这看起来像是在工作,直到我尝试使用移动构造函数:
#include <functional>
#include <tuple>
#include <utility>
template <typename R, typename D>
class Cleaner {
public:
Cleaner() = default;
Cleaner(R r, D d = {}) : data(std::move(d), std::move(r)), owns(true) {
}
~Cleaner() {
if (!owns) return;
std::apply(
[](auto&&... args){
std::invoke(std::forward<decltype(args)>(args)...);
},
std::move(data)
);
}
Cleaner(Cleaner&& other) noexcept {
swap(*this, other);
}
Cleaner& operator=(Cleaner&& other) noexcept {
swap(*this, other);
return *this;
}
void release() { owns = false; }
R& get() { return std::get<1>(data); }
R const& get() const { return std::get<1>(data); }
friend void swap(Cleaner& a, Cleaner& b) noexcept {
using std::swap;
swap(a.data, b.data);
swap(a.owns, b.owns);
}
private:
std::tuple<D, R> data;
bool owns = false;
};
#include <iostream>
int main() {
auto c = Cleaner(0, [](int){ std::cout << "clean\n"; });
auto a(std::move(c)); // <- this fails to compile
}
(编译报错信息太长复制到这里,不过你可以在这里看到:https://godbolt.org/z/5fqz5qTxT)
消息开头为:
source>: In instantiation of 'Cleaner<R, D>::Cleaner(Cleaner<R, D>&&) [with R = int; D = main()::<lambda(int)>]':
<source>:48:24: required from here
<source>:20:37: error: no matching function for call to 'std::tuple<main()::<lambda(int)>, int>::tuple()'
20 | Cleaner(Cleaner&& other) noexcept {
| ^
In file included from /opt/compiler-explorer/gcc-trunk-20220208/include/c++/12.0.1/functional:54,
from <source>:1:
/opt/compiler-explorer/gcc-trunk-20220208/include/c++/12.0.1/tuple:1259:9: note: candidate: 'template<class _Alloc, class _U1, class _U2, typename std::enable_if<__is_explicitly_constructible<_U1, _U2>(), bool>::type <anonymous> > std::tuple<_T1, _T2>::tuple(std::allocator_arg_t, const _Alloc&, std::pair<_U1, _U2>&&) [with _U1 = _Alloc; _U2 = _U1; typename std::enable_if<std::_TupleConstraints<true, _T1, _T2>::__is_explicitly_constructible<_U1, _U2>(), bool>::type <anonymous> = _U2; _T1 = main()::<lambda(int)>; _T2 = int]'
1259 | tuple(allocator_arg_t __tag, const _Alloc& __a, pair<_U1, _U2>&& __in)
| ^~~~~
[...]
有人可以帮助我了解问题所在以便我解决吗?
你的问题是 lambda 不是默认可构造的(non-capturing 是自 C++20 起)。
您可以将构造函数更改为:
Cleaner(Cleaner&& other) noexcept :
data(std::move(other.data)),
owns(other.owns)
{
other.owns = false;
}