I have a type effectively wrapping a variadic std::tuple
like this:
#include <iostream>
#include <tuple>
template <typename ...Args>
struct Foo {
std::tuple<Args...> t;
Foo(Args&&... a)
: t{ std::forward<Args>(a)... }
{ }
Foo& operator +=(const Foo& f) {
std::apply([&](auto&&... ts) {
std::apply([...ts = std::forward<decltype(ts)>(ts)](auto&&... fts) {
((ts += fts), ...);
}, f.t);
}, t);
return *this;
}
friend std::ostream& operator <<(std::ostream& os, const Foo& f) {
std::apply([&](auto&&... ts) {
((os << ts << ' '), ...);
}, f.t);
return os;
}
};
int main() {
Foo goy{ 1, 2, 3 };
Foo bar{ 4, 5, 6 };
goy += bar;
std::cout << goy << std::endl; // expect 5 7 9 as output
}
Now I want to be able to add-assign instances of this type by adding the tuple entries element-wise, as indicated in the code snippet and preferably with the use of fold-expressions instead of rather clumsy constructions using std::index_sequence<>
and alike. However, my attempt fails at the compiler level, with clang facing and internal compiler crash and GCC diagnosing:
error: assignment of read-only variable 'ts#0'
15 | ((ts += fts), ...);
| ~~~~^~~~~~~
I fail to see why ts
is immutable here. So what's wrong? Is the program ill-formed and/or are the compilers buggy? Is there an elegant fix?
lambda capture are
const
by default, you need to add mutable to mutate it.although I don't see why you capture it by value here, to me it seems like you actually want to capture them by reference.