Reputation: 21518
I am trying to implement a generic RAII cleanup. This looked like it was working, until I tried to use the move constructor:
#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
}
(The compile error message is to long to copy here, but you can see it here: https://godbolt.org/z/5fqz5qTxT)
The message starts with:
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)
| ^~~~~
[...]
Can someone help me understand what the problem is so I can fix it?
Upvotes: 2
Views: 100