enum like calculated constants
Clash Royale CLAN TAG#URR8PPP
up vote
6
down vote
favorite
Actually this "problem" feels extremely simple. While doing some calculated icon offsets, i came up with the following approach:
namespace Icons
struct IconSet
constexpr IconSet(size_t base_offset) noexcept
: base_offset_(base_offset), icon(base_offset * 3), iconSmall(icon + 1), iconBig(icon + 2)
size_t icon;
size_t iconSmall;
size_t iconBig;
size_t base_offset_;
constexpr size_t next() const
return base_offset_ + 1;
;
static constexpr IconSet flower = IconSet(0);
static constexpr IconSet tree = IconSet(flower.next());
static constexpr IconSet forest = IconSet(tree.next());
static constexpr IconSet mountain = IconSet(forest.next());
Now one may write Icons::tree.iconBig
for example to get that icons calculated offset. Basicly the designer can change the icons - sometimes adding/removing as well - but always has to provide the entire set (normal, small and big) by convention.
As you see, the issue with this approach is that I had to do that next()
function and use it repeatedly - a normal enum wouldn't have this downside.
I know of BOOST_PP and other macro tricks, but I was hoping for something without macro's - since i have a feeling it is not needed and I then sort of would prefer what I already have with the plain next()
function.
Another solution would of course just be a normal enum and a calculation function, but that is defeating the purpose of laying it out precalculated.
Hence, I am looking for a simple and portable solution that will give that enum like functionality. It doesn't have to be compile time or constexpr
if for example just inline will make it easier.
c++ c++17 constexpr
add a comment |Â
up vote
6
down vote
favorite
Actually this "problem" feels extremely simple. While doing some calculated icon offsets, i came up with the following approach:
namespace Icons
struct IconSet
constexpr IconSet(size_t base_offset) noexcept
: base_offset_(base_offset), icon(base_offset * 3), iconSmall(icon + 1), iconBig(icon + 2)
size_t icon;
size_t iconSmall;
size_t iconBig;
size_t base_offset_;
constexpr size_t next() const
return base_offset_ + 1;
;
static constexpr IconSet flower = IconSet(0);
static constexpr IconSet tree = IconSet(flower.next());
static constexpr IconSet forest = IconSet(tree.next());
static constexpr IconSet mountain = IconSet(forest.next());
Now one may write Icons::tree.iconBig
for example to get that icons calculated offset. Basicly the designer can change the icons - sometimes adding/removing as well - but always has to provide the entire set (normal, small and big) by convention.
As you see, the issue with this approach is that I had to do that next()
function and use it repeatedly - a normal enum wouldn't have this downside.
I know of BOOST_PP and other macro tricks, but I was hoping for something without macro's - since i have a feeling it is not needed and I then sort of would prefer what I already have with the plain next()
function.
Another solution would of course just be a normal enum and a calculation function, but that is defeating the purpose of laying it out precalculated.
Hence, I am looking for a simple and portable solution that will give that enum like functionality. It doesn't have to be compile time or constexpr
if for example just inline will make it easier.
c++ c++17 constexpr
add a comment |Â
up vote
6
down vote
favorite
up vote
6
down vote
favorite
Actually this "problem" feels extremely simple. While doing some calculated icon offsets, i came up with the following approach:
namespace Icons
struct IconSet
constexpr IconSet(size_t base_offset) noexcept
: base_offset_(base_offset), icon(base_offset * 3), iconSmall(icon + 1), iconBig(icon + 2)
size_t icon;
size_t iconSmall;
size_t iconBig;
size_t base_offset_;
constexpr size_t next() const
return base_offset_ + 1;
;
static constexpr IconSet flower = IconSet(0);
static constexpr IconSet tree = IconSet(flower.next());
static constexpr IconSet forest = IconSet(tree.next());
static constexpr IconSet mountain = IconSet(forest.next());
Now one may write Icons::tree.iconBig
for example to get that icons calculated offset. Basicly the designer can change the icons - sometimes adding/removing as well - but always has to provide the entire set (normal, small and big) by convention.
As you see, the issue with this approach is that I had to do that next()
function and use it repeatedly - a normal enum wouldn't have this downside.
I know of BOOST_PP and other macro tricks, but I was hoping for something without macro's - since i have a feeling it is not needed and I then sort of would prefer what I already have with the plain next()
function.
Another solution would of course just be a normal enum and a calculation function, but that is defeating the purpose of laying it out precalculated.
Hence, I am looking for a simple and portable solution that will give that enum like functionality. It doesn't have to be compile time or constexpr
if for example just inline will make it easier.
c++ c++17 constexpr
Actually this "problem" feels extremely simple. While doing some calculated icon offsets, i came up with the following approach:
namespace Icons
struct IconSet
constexpr IconSet(size_t base_offset) noexcept
: base_offset_(base_offset), icon(base_offset * 3), iconSmall(icon + 1), iconBig(icon + 2)
size_t icon;
size_t iconSmall;
size_t iconBig;
size_t base_offset_;
constexpr size_t next() const
return base_offset_ + 1;
;
static constexpr IconSet flower = IconSet(0);
static constexpr IconSet tree = IconSet(flower.next());
static constexpr IconSet forest = IconSet(tree.next());
static constexpr IconSet mountain = IconSet(forest.next());
Now one may write Icons::tree.iconBig
for example to get that icons calculated offset. Basicly the designer can change the icons - sometimes adding/removing as well - but always has to provide the entire set (normal, small and big) by convention.
As you see, the issue with this approach is that I had to do that next()
function and use it repeatedly - a normal enum wouldn't have this downside.
I know of BOOST_PP and other macro tricks, but I was hoping for something without macro's - since i have a feeling it is not needed and I then sort of would prefer what I already have with the plain next()
function.
Another solution would of course just be a normal enum and a calculation function, but that is defeating the purpose of laying it out precalculated.
Hence, I am looking for a simple and portable solution that will give that enum like functionality. It doesn't have to be compile time or constexpr
if for example just inline will make it easier.
c++ c++17 constexpr
c++ c++17 constexpr
asked 2 hours ago
darune
540212
540212
add a comment |Â
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
6
down vote
accepted
Here is an approach you can use, based on a fold expression over a compile time integer sequence to instantiate the icons by index. The structured binding gets you individually named non-static, non-constexpr variables.
The anonymous namespace inside Icons
makes those definitions visible in this translation unit only, which you may or may not want.
Compiler explorer link so you can explore the code options yourself.
#include <cstddef>
#include <array>
#include <utility>
namespace Icons
struct IconSet
constexpr IconSet(size_t base_offset) noexcept
: base_offset_(base_offset), icon(base_offset * 3), iconSmall(icon + 1), iconBig(icon + 2)
size_t icon;
size_t iconSmall;
size_t iconBig;
size_t base_offset_;
;
template <std::size_t... Ints>
constexpr auto make_icons_helper(std::index_sequence<Ints...>) -> std::array<IconSet, sizeof...(Ints)>
return IconSet(Ints)...;
template <size_t N>
constexpr auto make_icons()
return make_icons_helper(std::make_index_sequence<N>);
namespace
auto [flower, tree, forest, mountain] = make_icons<4>();
int main()
return Icons::forest.iconSmall;
add a comment |Â
up vote
2
down vote
A simple, non-constexpr solution using a static counter and relying on the fact that static initialization is performed top-to-bottom within a single TU:
namespace Icons
namespace detail_iconSet
static std::size_t current_base_offset = 0;
struct IconSet
IconSet() noexcept
: base_offset_(detail_iconSet::current_base_offset++)
, icon(base_offset_ * 3)
, iconSmall(icon + 1)
, iconBig(icon + 2)
std::size_t base_offset_;
std::size_t icon;
std::size_t iconSmall;
std::size_t iconBig;
;
static IconSet flower;
static IconSet tree;
static IconSet forest;
static IconSet mountain;
See it live on Coliru
The catch is that this will behave weirdly if you have several headers containing IconSet
definitions (i.e. their numbering will change depending on the order of inclusion), but then I don't think there's a way to avoid that.
This will need a big fat comment to point out that it's relying on static initialization order.
– Max Langhof
1 hour ago
1
@MaxLanghof should I put the very first sentence in title font? :p
– Quentin
1 hour ago
1
I didn't mean "your answer fails to mention the fact" but "this is really fragile code and should be very clearly marked as such before going anywhere close to production". ;)
– Max Langhof
1 hour ago
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
6
down vote
accepted
Here is an approach you can use, based on a fold expression over a compile time integer sequence to instantiate the icons by index. The structured binding gets you individually named non-static, non-constexpr variables.
The anonymous namespace inside Icons
makes those definitions visible in this translation unit only, which you may or may not want.
Compiler explorer link so you can explore the code options yourself.
#include <cstddef>
#include <array>
#include <utility>
namespace Icons
struct IconSet
constexpr IconSet(size_t base_offset) noexcept
: base_offset_(base_offset), icon(base_offset * 3), iconSmall(icon + 1), iconBig(icon + 2)
size_t icon;
size_t iconSmall;
size_t iconBig;
size_t base_offset_;
;
template <std::size_t... Ints>
constexpr auto make_icons_helper(std::index_sequence<Ints...>) -> std::array<IconSet, sizeof...(Ints)>
return IconSet(Ints)...;
template <size_t N>
constexpr auto make_icons()
return make_icons_helper(std::make_index_sequence<N>);
namespace
auto [flower, tree, forest, mountain] = make_icons<4>();
int main()
return Icons::forest.iconSmall;
add a comment |Â
up vote
6
down vote
accepted
Here is an approach you can use, based on a fold expression over a compile time integer sequence to instantiate the icons by index. The structured binding gets you individually named non-static, non-constexpr variables.
The anonymous namespace inside Icons
makes those definitions visible in this translation unit only, which you may or may not want.
Compiler explorer link so you can explore the code options yourself.
#include <cstddef>
#include <array>
#include <utility>
namespace Icons
struct IconSet
constexpr IconSet(size_t base_offset) noexcept
: base_offset_(base_offset), icon(base_offset * 3), iconSmall(icon + 1), iconBig(icon + 2)
size_t icon;
size_t iconSmall;
size_t iconBig;
size_t base_offset_;
;
template <std::size_t... Ints>
constexpr auto make_icons_helper(std::index_sequence<Ints...>) -> std::array<IconSet, sizeof...(Ints)>
return IconSet(Ints)...;
template <size_t N>
constexpr auto make_icons()
return make_icons_helper(std::make_index_sequence<N>);
namespace
auto [flower, tree, forest, mountain] = make_icons<4>();
int main()
return Icons::forest.iconSmall;
add a comment |Â
up vote
6
down vote
accepted
up vote
6
down vote
accepted
Here is an approach you can use, based on a fold expression over a compile time integer sequence to instantiate the icons by index. The structured binding gets you individually named non-static, non-constexpr variables.
The anonymous namespace inside Icons
makes those definitions visible in this translation unit only, which you may or may not want.
Compiler explorer link so you can explore the code options yourself.
#include <cstddef>
#include <array>
#include <utility>
namespace Icons
struct IconSet
constexpr IconSet(size_t base_offset) noexcept
: base_offset_(base_offset), icon(base_offset * 3), iconSmall(icon + 1), iconBig(icon + 2)
size_t icon;
size_t iconSmall;
size_t iconBig;
size_t base_offset_;
;
template <std::size_t... Ints>
constexpr auto make_icons_helper(std::index_sequence<Ints...>) -> std::array<IconSet, sizeof...(Ints)>
return IconSet(Ints)...;
template <size_t N>
constexpr auto make_icons()
return make_icons_helper(std::make_index_sequence<N>);
namespace
auto [flower, tree, forest, mountain] = make_icons<4>();
int main()
return Icons::forest.iconSmall;
Here is an approach you can use, based on a fold expression over a compile time integer sequence to instantiate the icons by index. The structured binding gets you individually named non-static, non-constexpr variables.
The anonymous namespace inside Icons
makes those definitions visible in this translation unit only, which you may or may not want.
Compiler explorer link so you can explore the code options yourself.
#include <cstddef>
#include <array>
#include <utility>
namespace Icons
struct IconSet
constexpr IconSet(size_t base_offset) noexcept
: base_offset_(base_offset), icon(base_offset * 3), iconSmall(icon + 1), iconBig(icon + 2)
size_t icon;
size_t iconSmall;
size_t iconBig;
size_t base_offset_;
;
template <std::size_t... Ints>
constexpr auto make_icons_helper(std::index_sequence<Ints...>) -> std::array<IconSet, sizeof...(Ints)>
return IconSet(Ints)...;
template <size_t N>
constexpr auto make_icons()
return make_icons_helper(std::make_index_sequence<N>);
namespace
auto [flower, tree, forest, mountain] = make_icons<4>();
int main()
return Icons::forest.iconSmall;
edited 2 hours ago
answered 2 hours ago
Bruce Collie
3435
3435
add a comment |Â
add a comment |Â
up vote
2
down vote
A simple, non-constexpr solution using a static counter and relying on the fact that static initialization is performed top-to-bottom within a single TU:
namespace Icons
namespace detail_iconSet
static std::size_t current_base_offset = 0;
struct IconSet
IconSet() noexcept
: base_offset_(detail_iconSet::current_base_offset++)
, icon(base_offset_ * 3)
, iconSmall(icon + 1)
, iconBig(icon + 2)
std::size_t base_offset_;
std::size_t icon;
std::size_t iconSmall;
std::size_t iconBig;
;
static IconSet flower;
static IconSet tree;
static IconSet forest;
static IconSet mountain;
See it live on Coliru
The catch is that this will behave weirdly if you have several headers containing IconSet
definitions (i.e. their numbering will change depending on the order of inclusion), but then I don't think there's a way to avoid that.
This will need a big fat comment to point out that it's relying on static initialization order.
– Max Langhof
1 hour ago
1
@MaxLanghof should I put the very first sentence in title font? :p
– Quentin
1 hour ago
1
I didn't mean "your answer fails to mention the fact" but "this is really fragile code and should be very clearly marked as such before going anywhere close to production". ;)
– Max Langhof
1 hour ago
add a comment |Â
up vote
2
down vote
A simple, non-constexpr solution using a static counter and relying on the fact that static initialization is performed top-to-bottom within a single TU:
namespace Icons
namespace detail_iconSet
static std::size_t current_base_offset = 0;
struct IconSet
IconSet() noexcept
: base_offset_(detail_iconSet::current_base_offset++)
, icon(base_offset_ * 3)
, iconSmall(icon + 1)
, iconBig(icon + 2)
std::size_t base_offset_;
std::size_t icon;
std::size_t iconSmall;
std::size_t iconBig;
;
static IconSet flower;
static IconSet tree;
static IconSet forest;
static IconSet mountain;
See it live on Coliru
The catch is that this will behave weirdly if you have several headers containing IconSet
definitions (i.e. their numbering will change depending on the order of inclusion), but then I don't think there's a way to avoid that.
This will need a big fat comment to point out that it's relying on static initialization order.
– Max Langhof
1 hour ago
1
@MaxLanghof should I put the very first sentence in title font? :p
– Quentin
1 hour ago
1
I didn't mean "your answer fails to mention the fact" but "this is really fragile code and should be very clearly marked as such before going anywhere close to production". ;)
– Max Langhof
1 hour ago
add a comment |Â
up vote
2
down vote
up vote
2
down vote
A simple, non-constexpr solution using a static counter and relying on the fact that static initialization is performed top-to-bottom within a single TU:
namespace Icons
namespace detail_iconSet
static std::size_t current_base_offset = 0;
struct IconSet
IconSet() noexcept
: base_offset_(detail_iconSet::current_base_offset++)
, icon(base_offset_ * 3)
, iconSmall(icon + 1)
, iconBig(icon + 2)
std::size_t base_offset_;
std::size_t icon;
std::size_t iconSmall;
std::size_t iconBig;
;
static IconSet flower;
static IconSet tree;
static IconSet forest;
static IconSet mountain;
See it live on Coliru
The catch is that this will behave weirdly if you have several headers containing IconSet
definitions (i.e. their numbering will change depending on the order of inclusion), but then I don't think there's a way to avoid that.
A simple, non-constexpr solution using a static counter and relying on the fact that static initialization is performed top-to-bottom within a single TU:
namespace Icons
namespace detail_iconSet
static std::size_t current_base_offset = 0;
struct IconSet
IconSet() noexcept
: base_offset_(detail_iconSet::current_base_offset++)
, icon(base_offset_ * 3)
, iconSmall(icon + 1)
, iconBig(icon + 2)
std::size_t base_offset_;
std::size_t icon;
std::size_t iconSmall;
std::size_t iconBig;
;
static IconSet flower;
static IconSet tree;
static IconSet forest;
static IconSet mountain;
See it live on Coliru
The catch is that this will behave weirdly if you have several headers containing IconSet
definitions (i.e. their numbering will change depending on the order of inclusion), but then I don't think there's a way to avoid that.
answered 2 hours ago
Quentin
42.5k575130
42.5k575130
This will need a big fat comment to point out that it's relying on static initialization order.
– Max Langhof
1 hour ago
1
@MaxLanghof should I put the very first sentence in title font? :p
– Quentin
1 hour ago
1
I didn't mean "your answer fails to mention the fact" but "this is really fragile code and should be very clearly marked as such before going anywhere close to production". ;)
– Max Langhof
1 hour ago
add a comment |Â
This will need a big fat comment to point out that it's relying on static initialization order.
– Max Langhof
1 hour ago
1
@MaxLanghof should I put the very first sentence in title font? :p
– Quentin
1 hour ago
1
I didn't mean "your answer fails to mention the fact" but "this is really fragile code and should be very clearly marked as such before going anywhere close to production". ;)
– Max Langhof
1 hour ago
This will need a big fat comment to point out that it's relying on static initialization order.
– Max Langhof
1 hour ago
This will need a big fat comment to point out that it's relying on static initialization order.
– Max Langhof
1 hour ago
1
1
@MaxLanghof should I put the very first sentence in title font? :p
– Quentin
1 hour ago
@MaxLanghof should I put the very first sentence in title font? :p
– Quentin
1 hour ago
1
1
I didn't mean "your answer fails to mention the fact" but "this is really fragile code and should be very clearly marked as such before going anywhere close to production". ;)
– Max Langhof
1 hour ago
I didn't mean "your answer fails to mention the fact" but "this is really fragile code and should be very clearly marked as such before going anywhere close to production". ;)
– Max Langhof
1 hour ago
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53079665%2fenum-like-calculated-constants%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password