I want to provide structured binding for an inner class of a class template. How can I specialise std::tuple_size
for that inner class?
I can't use structured binding to data member, because the inner class may be a type incompatible with that feature. So I need to provide tuple-like structured binding.
To provide such a feature to the inner class I need to partially specialise std::tuple_size
in namespace std
. The problem is that I got a non-deduced context for the parameter T
(of the outer class).
I know that I could put the inner class in the global namespace and thus solve every problem, but is there any way to get the same result keeping the class inner?
#include <tuple>
template<typename T>
class Collection
{
public:
struct Element
{
int id;
T actual_element;
};
//...
};
namespace std
{
template<typename T>
struct tuple_size<typename Collection<T>::Element> // Error! Non-deduced context
: std::integral_constant<std::size_t, 2> {};
}
//Collection iterators...
int main()
{
Collection<int> collection;
for (auto & [id, element] : collection) //what I'd like to achieve
//do some stuff...
}
You don't have to provide a binding for this case: Element
is already decomposable as is:
struct Element { int i, j; };
auto [i, j] = Element{2, 3}; // ok
However, assuming Element
is actually more complex and needs custom bindings, then yes - you will need to move it out. However, it doesn't need to be in a global namespace. It could be somewhere else:
namespace detail {
template <typename T> struct Element { ... };
}
template<typename T>
class Collection
{
public:
using Element = detail::Element<T>;
friend Element;
// ...
};
And at that point, specializing the bindings is straightforward. There is no way around† that since, as you point out, specializing on Collection<T>::Element
is a non-deduced context.
†Short of a new language feature that would let you opt-in to structured bindings within the class body itself. There was such a paper for this, P1096, but it was rejected when presented. Which isn't to say a new proposal couldn't do better.