Info
-
Did you know that ANSI/ISO C++ conforming programs must not rely on a maximum template depth greater than 17 (changed to 1024 in C++11)?
Example
template<auto N> struct type { static constexpr auto id = N; };
template <class T, class... Ts> [[nodiscard]] constexpr auto get(auto& t, const auto id) -> void* {
if (id == T::id) {
return std::addressof(std::get<T>(t));
} else if constexpr(sizeof...(Ts) > 0) {
return get<Ts...>(t, id);
} else {
return nullptr;
}
}
int main (){
std::tuple t{"foo", type<0>{}, 42, type<1>{}, type<99>{}, type<42>{}};
assert((get<type<0>, type<1>>(t, 0)));
assert((get<type<0>, type<1>>(t, 1)));
assert(not (get<type<0>, type<1>>(t, 42)));
}
Puzzle
-
Can you implement function
get
which returns a void pointer to an object from unique list of inherited types based on run-time id and avoids template depth recursion?- Double points for the solution fastest to compile
template <auto N> struct type { static constexpr auto id = N; };
template<class... TArgs>
struct data : TArgs... {
constexpr explicit(false) data(TArgs... args) : TArgs{args}... { }
[[nodiscard]] constexpr auto get(const auto id) -> void *; // TODO
};
int main() {
data d{
type<0>{},
type<1>{},
type<2>{},
type<3>{},
...
type<1025>{}
};
assert(nullptr != d.get(0));
assert(nullptr != d.get(1));
assert(nullptr != d.get(2));
assert(nullptr != d.get(3));
...
assert(nullptr == d.get(1001));
assert(nullptr != d.get(10010));
...
assert(nullptr == d.get(1020));
assert(nullptr != d.get(10200));
...
}
Solutions
template<class... TArgs>
struct data : TArgs... {
constexpr explicit(false) data(TArgs... args) : TArgs{args}... { }
[[nodiscard]] constexpr auto get(const auto id) -> void * {
void* p = nullptr;
(... or (p = TArgs::id == id ? static_cast<TArgs*>(this) : nullptr));
return p;
}
};
template<class... TArgs>
struct data : TArgs... {
constexpr explicit(false) data(TArgs... args) : TArgs{args}... { }
[[nodiscard]] constexpr auto get(const auto id) -> void * {
void* addressofs[]{static_cast<void*>(static_cast<TArgs *>(this))...};
decltype(id) ids[]{TArgs::id...};
const auto it = std::find(std::cbegin(ids), std::cend(ids), id);
return it != std::cend(ids) ? addressofs [ std::size_t(std::distance(std::cbegin(ids), it)) ] : nullptr;
}
};
template<class... TArgs>
struct data : TArgs... {
constexpr explicit(false) data(TArgs... args) : TArgs{args}... { }
[[nodiscard]] constexpr void * get(const int id) {
constexpr int ids[]{ TArgs::id... };
for (std::size_t i = 0; i < sizeof...(TArgs); ++i) {
if (ids[i] == id) return this;
}
return nullptr;
}
};
template<class... TArgs>
struct data : TArgs... {
static constexpr int ids[]{ TArgs::id... };
constexpr explicit(false) data(TArgs... args) : TArgs{args}... { }
[[nodiscard]] constexpr auto get(const auto id) -> void * {
auto it = std::find(std::begin(ids), std::end(ids), id );
if(it == std::end(ids))
{
return nullptr;
}
return this;
}
};
template<class... TArgs>
struct data : TArgs... {
constexpr explicit(false) data(TArgs... args) : TArgs{args}... { }
static constexpr int ids[] = { TArgs::id... };
[[nodiscard]] constexpr auto get(const auto id) -> void * {
const auto it = std::ranges::find(ids, id);
return it != std::cend(ids) ? this : nullptr;
}
};
template<class... TArgs>
struct data : TArgs... {
constexpr explicit(false) data(TArgs... args) : TArgs{args}... { }
[[nodiscard]] constexpr auto get(const auto id) -> void * {
int ids[] = {TArgs::id...};
for(int i=0; i<sizeof...(TArgs); i++)
if( id == ids[i])
return (void*)this;
return nullptr;
}
};
template<class... TArgs>
struct data : TArgs... {
constexpr explicit(false) data(TArgs... args) : TArgs{args}... { }
[[nodiscard]] constexpr auto get(const auto id) -> void *
{
constexpr int N = sizeof ...(TArgs) ;
int ids[N] = { TArgs::id... };
void* ptrs[N] = { (dynamic_cast<TArgs*>(this)) ... };
for( int i = 0; i < N ; ++i )
if( id == ids[i])
return ptrs[i];
return nullptr;
}
};
template<class... TArgs>
struct data : TArgs... {
constexpr explicit(false) data(TArgs... args) : TArgs{args}... { }
[[nodiscard]] constexpr auto get(const auto id) -> void * {
return (void*)((TArgs::id == id ? (std::size_t)static_cast<TArgs*>(this) : 0) + ...);
}
};