https://wg21.link/P2996 allows form of stateful meta-programming without using friend injection.
Meta-counter is pretty easy - https://godbolt.org/z/91M56a5dd as we just iterate over complete instantiations of the counter class (tricky part is to force the instantiation).
The following is a bit more complex example of stateful meta-programming - compile-time type list.
Firstly, C++20 version (based on friend injection) - works on gcc,clang,msvc
template<class...> struct type_list {};
namespace detail {
template<auto> struct nth { auto friend get(nth); auto friend get(nth); };
template<auto N, class T> struct set { auto friend get(nth<N>) { return T{}; } };
template<class T, template<class...> class TList, class... Ts> auto append(TList<Ts...>) -> TList<Ts..., T>;
} // namespace detail
template<class T, auto N = 0, auto unique = []{}>
consteval auto append() {
if constexpr (requires { get(detail::nth<N>{}); }) {
append<T, N+1, unique>();
} else if constexpr (N == 0) {
void(detail::set<N, type_list<T>>{});
} else {
void(detail::set<N, decltype(detail::append<T>(get(detail::nth<N-1>{})))>{});
}
}
template<auto unique = []{}, auto N = 0>
consteval auto get_list() {
if constexpr (requires { get(detail::nth<N>{}); }) {
return get_list<unique, N+1>();
} else if constexpr (N == 0) {
return type_list{};
} else {
return get(detail::nth<N-1>{});
}
}
int main() {
static_assert(typeid(get_list()) == typeid(type_list<>));
append<int>();
static_assert(typeid(get_list()) == typeid(type_list<int>));
append<float>();
static_assert(typeid(get_list()) == typeid(type_list<int, float>));
}
Meta-counter is pretty easy - https://godbolt.org/z/91M56a5dd as we just iterate over complete instantiations of the counter class (tricky part is to force the instantiation).
The following is a bit more complex example of stateful meta-programming - compile-time type list.
Firstly, C++20 version (based on friend injection) - works on gcc,clang,msvc
Full example -> https://godbolt.org/z/axPT88e3cNow, C++26 version with the reflection proposal (based on injecting classes with members) - works on EDG
Full example -> https://godbolt.org/z/5s8YvYqqr