given following templates and specialization
enum CountryName
{
Armenia = 0 ,
Georgia,
Size = 2
};
template <CountryName variable>
class CountryInfo;
template <>
class CountryInfo<Armenia>
{
/* CODE HERE */
};
template <>
class CountryInfo<Georgia>
{
/* CODE HERE */
};
I would like to iterate over enum and create object for each specialization.
main() {
for(auto i=0; i<CountryName::Size; ++i) {
CountryInfo<(static_cast<CountryName>(i))>();
}
}
I get following error: error: the value of 'i' is not usable in a constant expression CountryInfo<(static_cast(i))>();
What you want is convert a run-time variable into a compile-time variable (which is the requirement for a template argument). There are various ways to achieve this, for example
enum struct Country {
Armenia, Georgia, India
};
template<template<County> class Functor, typename... Args>
void LoopCountries(Args&&...args)
{
{ Functor<Armenia> func; func(std::forward<Args>(args)...); }
{ Functor<Georgia> func; func(std::forward<Args>(args)...); }
{ Functor<India> func; func(std::forward<Args>(args)...); }
}
which assumes that Functor<>
has a member operator()
. Now you can simply
LoopCountries<CountryInfo>();
A more common situation is to pick one value (instead of looping over all):
template<template<County> class Functor, typename... Args>
void SwitchCountry(Country country, Args&&...args)
{
switch(country) {
case Armenia: { Functor<Armenia> func; func(std::forward<Args>(args)...); }
case Georgia: { Functor<Georgia> func; func(std::forward<Args>(args)...); }
case India: { Functor<India> func; func(std::forward<Args>(args)...); }
}
}
As I said in the comments, templates are resolved at compile-time. I.e. only constant values can be used as template parameters, which the variable i
is not.
What you can do is some kind of recursive template iteration:
template<CountryName c>
struct ForLoop {
template<template <CountryName> class Func>
static void iterate() {
ForLoop<static_cast<CountryName>(c - 1)>::template iterate<Func>();
Func<c>()();
}
};
//so that compiler knows when to stop
template <>
struct ForLoop<Armenia> {
template <template <CountryName> class Func>
static void iterate() {
Func<Armenia>()();
}
};
// CountryInfo needs an overloaded ()-operator, whcih get's called in the ForLoop
template <CountryName n>
struct CountryInfo {
void operator()() { std::cout << n << std::endl; }
};
int main() {
ForLoop<Georgia>::iterate<CountryInfo>();
return 0;
}
In the main
-function the static ForLoop<Georgia>::iterate
-function get's called, this function then substracts 1 from Georgia and calls the function iterate
again, until it hits the ForLoop<Armenia>::iterate
which is the last function which get's called.
In case you have any questions, let me know.
As explained by Mike van Dike, a template parameter needs to be known compile-time but your i
is modified run time.
You have to use compile-time known indexes.
If you can use C++14, you can use variadic templates, std::make_index_sequence
and std::index_sequence
so you can do something as follows (see iterateCountry()
)
#include <tuple>
#include <type_traits>
enum CountryName
{
Armenia = 0 ,
Georgia,
Size = 2
};
template <CountryName variable>
class CountryInfo;
template <>
class CountryInfo<Armenia>
{
/* CODE HERE */
};
template <>
class CountryInfo<Georgia>
{
/* CODE HERE */
};
template <std::size_t ... Is>
auto iterateCountry (std::index_sequence<Is...> const &)
{ return std::make_tuple(CountryInfo<static_cast<CountryName>(Is)>{}...); }
int main ()
{
auto ict { iterateCountry(
std::make_index_sequence<static_cast<std::size_t>(
CountryName::Size)>{}) };
static_assert(std::is_same<decltype(ict),
std::tuple<CountryInfo<Armenia>,
CountryInfo<Georgia>>>{}, "!");
}
-- EDIT --
The OP ask
I was seeking for way to somehow iterate over countries and create objects. link line 5344.
It seem's to me that my solution make exactly this.
For your line 5344 case, I suppose you should apply my solution adding a delegating constructor; something as
template <std::size_t ... Is>
CountryInfoManager (std::index_sequence<Is...> const &)
: m_countries{ new CountryInfo<static_cast<CountryName>(Is)>{}... }
{ }
CountryInfoManager ()
: CountryInfoManager(
std::make_index_sequence<static_cast<std::size_t>(
CountryName::Size)>{})
{ }
You could use something like this:
template<std::size_t... I>
constexpr auto
countries(std::index_sequence<I...>)
{
return std::make_tuple(CountryInfo<static_cast<CountryName>(I)>{}...);
}
constexpr auto
all_countries()
{
return countries(std::make_index_sequence<Size>());
}
The result will be a tuple, with each index containing a country of corresponding type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With