Currently using g++11.3.0, C++20.
Could anyone explain how the basic_registry's get<>()
template function is able to function such that when retrieving a single component through a call like auto& comp {registry.get<A>()};
, the component itself can be directly assigned to and/or accessed like a normal reference, and when retrieving multiple components through a call like registry.get<A, B, C>()
, it can be unpacked via a structured binding auto& [a, b, c]
.
Code (from https://skypjack.github.io/entt/registry_8hpp_source.html)
template<typename... Type>
[[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) {
if constexpr(sizeof...(Type) == 1u) {
return (const_cast<Type &>(std::as_const(*this).template get<Type>(entt)), ...);
} else {
return std::forward_as_tuple(get<Type>(entt)...);
}
}
The following function template returns a tuple:
template <typename ...T>
auto foo() {
return std::make_tuple(T{}...);
}
You can call it via
auto [a, b, c] = foo<int,int,double>();
The following function template returns just a T
:
template <typename T>
auto bar() { return T{};}
you can call it via
auto d{bar<int>()};
Functions can have only one return type. foo
and bar
are function templates. The functions foo<int,int,double>
and bar<int>
have one return type. They return one value.
The following function template selects between two function templates to be instantiated and called depending on the number of template arguments:
template <typename ...T>
auto moo() {
if constexpr(sizeof...(T) == 1u) { return bar<T...>(); }
else return foo<T...>();
}
You can call it via:
auto [x,y,z] = moo<int,int,double>();
Or
auto w{ moo<int>()};
Note that when T...
is more than a single argument then bar<T...>
would be a mismatch (because bar
has only a single argument. However, with constexpr if
in template context the not taken branch is discarded at compile time.
In the case of sizeof...(T) == 1u
the parameter pack is expanded. However, the expansion is only a single type in this case (otherwise bar<T...>
would not compile). It could have been written as
template <typename T,typename ...More>
auto moo() {
if constexpr(sizeof...(More) == 0u) { return bar<T>(); }
else return foo<T,More...>();
}