While implementing a compressed_tuple
class for some project I'm working on, I ran into the following issue: I can't seem to pass instances of this type to std::apply, even though this should be possible according to: https://en.cppreference.com/w/cpp/utility/apply.
I managed to reproduce the issue quite easily, using the following fragment (godbolt):
#include <tuple>
struct Foo {
public:
explicit Foo(int a) : a{ a } {}
auto &get_a() const { return a; }
auto &get_a() { return a; }
private:
int a;
};
namespace std {
template<>
struct tuple_size<Foo> {
constexpr static auto value = 1;
};
template<>
struct tuple_element<0, Foo> {
using type = int;
};
template<size_t I>
constexpr auto get(Foo &t) -> int & {
return t.get_a();
}
template<size_t I>
constexpr auto get(const Foo &t) -> const int & {
return t.get_a();
}
template<size_t I>
constexpr auto get(Foo &&t) -> int && {
return std::move(t.get_a());
}
template<size_t I>
constexpr auto get(const Foo &&t) -> const int && {
return move(t.get_a());
}
} // namespace std
auto foo = Foo{ 1 };
auto f = [](int) { return 2; };
auto result = std::apply(f, foo);
When I try to compile this piece of code, it seems that it cannot find the std::get
overloads that I have defined, even though they should perfectly match. Instead, it tries to match all of the other overloads (std::get(pair<T, U>), std::get(array<...>), etc.), while not even mentioning my overloads. I get consistent errors in all three major compilers (MSVC, Clang, GCC).
So my question is whether this is expected behavior and it's simply not possible to use std::apply
with user-defined types? And is there a work-around?
No, there is currently no way.
In libstdc++, libc++, and MSVC-STL implementations,
std::apply
usesstd::get
internally instead of unqualifiedget
, since users are prohibited from definingget
undernamespace std
, it is impossible to applystd::apply
to user-defined types.You may ask, in [tuple.creation], the standard describes
tuple_cat
as follows:Does this indicate that other
tuple
utility functions such asstd::apply
should support user-definedtuple
-like types?Note that in particular, the term "
tuple
-like" has no concrete definition at this point of time. This was intentionally left C++ committee to make this gap being filled by a future proposal. There exists a proposal that is going to start improving this matter, see P2165R3.Before P2165 is adopted, unfortunately, you may have to implement your own
apply
and use non-qualifiedget
.