> template<typename... Ts>
> class tuple {
>   Ts... elems;
> };

This is a thing of beauty :-)
The only drawback: I would actually like to be have "real" names for
members. That would allow to use

    auto x = t.m1;

instead of

    auto x = get<1>(t);

In my view, we should be able to treat tuples as structs and structs as
tuples. We just spell them differently. For instance, std::get would
work with structs. And I could also pass structs into tuple_cat.

Naming members of tuple falls into that category of "the next problem". We can do this with injection, but it can be much less elegant. Fortunately, we have functions to hide complexity.

template<typename... Ts>
struct tuple {
  consteval -> gen_tuple_members(^Ts...);
};

We should be able to make std::get<> work with structs with just reflection:

template<std::size_t N, plain_struct T>
decltype(auto) get(const T& obj) {
  return obj.[:data_members_of(^T)[N]:];
}

That can get a little more complicated when you add inheritance and access specifiers, but not much. Although, now that I think about, we could just replace the usual definition of std::get with something like this, and it automatically works for both tuples and structs. A little constexpr if sprinkled in there also makes it work for arrays.

I will continue avoiding tuple cat for now :)

(Every time I see "tuple cat" or tuple_cat, I keep wanting to read it as "Honky Cat", as in the Elton John song).

> constexpr tuple(T const&... args)
>   : ... [: data_members_of(^tuple) :]([:parameters_of(current_function()):])
> { }

While Barry's proposal is much shorter, I would prefer something like
this, as it would work with named members :-)

The idea of declaring packs vs. naming members is interesting. There are design objectives that motivate both uses, but I don't know if there are obvious criteria that push a design in either direction. Maybe it's just "I want names" vs. "I don't care about names".

 
So yes, go and find examples that are hard/clumsy without reflection and
start translating them. We need real life examples :-)

My experience has been that it is very hard to simultaneously design and implement language features and also dogfood them. It's also more than a bit self-reinforcing. Having other people bring problems --- which you have a great history of :) is excellent fodder for design discussions.

Andrew