Enum like calculated constants - c++

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 icon's calculated offset. Basically 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.

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;
}

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.

Related

Inline constexpr and anonymous namespace variables?

I have the following problem. In a .hpp file I have a function Space::foo() that must use a namespace global variable, I thought of hiding it in an anonymous namespace. But now I wonder, do I risk having values defined in each translation unit with multiple copies or there will only be one? Thanks for helping. This comes from the fact that I needed a bunch of functions in the Space namespace with a sort of private data part (the anonymous namespace stuff) so that Space is sort of like a class with only static members, but I don't want to have multiple copies of these variables if I include the .hpp file in different units.
// .hpp file
#include <array>
namespace Space {
namespace {
constexpr std::array<int, 10000> fill() { /* ... */ };
inline constexpr std::array<int, 10000> values = fill();
}
inline int foo(int i) {
return values[i];
}
}
do I risk having values defined in each translation unit with multiple copies
Yes. You'll have one definition of values in each TU. You can't declare it extern constexpr either because [dcl.constexpr]/1 says "The constexpr specifier shall be applied only to the definition of a variable".
Since the purpose seems to be to be able to pick values that are constant evaluated you could possibly make both fill and foo consteval and skip <anonymous>::values.
namespace Space {
namespace {
consteval std::array<int, 10000> fill() {
return {}; // replace with your filling algorithm
};
}
inline consteval int foo(size_t i) {
return fill()[i];
}
inline consteval int bar(size_t i, size_t j) {
constexpr auto values = fill();
return values[i] + values[j];
}
}
This would make it possible for foo and any other consteval function to use the algorithm in fill() and to use the result in constexpr/consteval situations.
constexpr auto x = Space::bar(10, 20);

Initialization of static constexpr class member dependent on template argument type

It appears that I still do not understand C++'s constexpr well enough and come across weird aspects almost every day. Here I would like to ask about one specifically:
struct Part1 {
static constexpr int size = 10;
};
struct Part2 {
static constexpr int size = 24;
};
template<class ... Part>
struct Assembly {
// this does not compile ...
// static constexpr int sizeDirect = (... + Part::size);
// this works, Assembly<Part1, Part2>::sizeFromFct is 34
static constexpr int sumUp() { return (... + Part::size); }
static constexpr int sizeFromFct = sumUp();
};
I am testing with MSVC 2017 in conformant mode (/permissive-), and of course C++17.
Why does the first version not compile but the second one does? Can sizeDirect be made to work with some syntax tweak?

Undefined reference to static constexpr member only used by value

I was trying to create a clever class containing a font style. Before this consisted of 3 enums with bit-wise compatible values (each set of values did not had overlapping bits with the other enums) so you could do FontStyle::LEFT | FontStyle::TOP
But clang warned me about combining unrelated enums and yes I've seen possible bugs here: FontStyle::LEFT | FontStyle::RIGHT did set both bits. So I reworked the class using a helper class for the former enums and templates to match correct values. But now I'm getting linker errors for clang on Debug builds about undefined reference to my static constexpr members.
Looking at Undefined reference error for static constexpr member suggests, that the value is ODR-used, but I'm not using any references.
When does a static constexpr class member need an out-of-class definition? this then pointed me to the implicit copy constructor of my helper class which is the issue.
Is there any chance I can avoid the out-of-class definitions in C++14 (C++17 already allows to omit them) and Debug builds (Ctors are optimized away in Release and hence no undefined references)?
Related code:
#include <array>
#include <cstdint>
namespace detail {
template<unsigned T_index>
struct FontStylePart
{
constexpr FontStylePart(uint8_t val) : value(val) {}
uint8_t value;
};
} // namespace detail
class FontStyle
{
static constexpr unsigned AlignH = 0;
static constexpr unsigned AlignV = 1;
public:
constexpr FontStyle() = default;
template<unsigned T_index>
constexpr FontStyle(detail::FontStylePart<T_index> style) : FontStyle()
{
value[T_index] = style.value;
}
/// Horizontal align
static constexpr detail::FontStylePart<AlignH> LEFT = 0;
static constexpr detail::FontStylePart<AlignH> RIGHT = 1;
static constexpr detail::FontStylePart<AlignH> CENTER = 2;
/// Vertical align
static constexpr detail::FontStylePart<AlignV> TOP = 0;
static constexpr detail::FontStylePart<AlignV> BOTTOM = 1;
static constexpr detail::FontStylePart<AlignV> VCENTER = 2;
private:
std::array<uint8_t, 3> value = {{0, 0, 0}};
};
int main() {
FontStyle style = FontStyle::CENTER;
return 0;
}
The line
FontStyle style = FontStyle::CENTER;
is a ODR use of FontStyle::CENTER.
I tried using
constexpr FontStyle style = FontStyle::CENTER;
but I ran into problems in the constructor. The following works although it's not clear to me whether that is acceptable for your needs.
int main() {
constexpr auto v = FontStyle::CENTER;
FontStyle style = v;
return 0;
}
This transfers the onus of ODR use to constexpr auto v.

Is it possible to calculate number factorial at compile time, but without enums

I want to calculate factorial at the compile-time. I found some way to solve the problem, but I want to know if there any another solution for this problem without using enum s. Here the solution using enum s.
#include <iostream>
template <int n>
struct fact
{
enum{value = n*fact<n-1>::value};
};
template<>
struct fact<1>
{
enum{value = 1};
};
int main()
{
std::cout << fact<10>::value;
}
If there is no another solution, please describe why the enum s are must.
While there are alternative notations, It's written that way because more compilers accept that enum-style notation. The language supports const integral-type class members with an inline initialization, but some compilers aren't compliant with the standard in that regard. On compilers that are compliant in this regard, the following works just fine:
#include <iostream>
template <unsigned int n>
struct fact
{
static const unsigned int value = n*fact<n-1>::value;
};
template<>
struct fact<0>
{
static const unsigned int value = 1;
};
int main()
{
std::cout << fact<10>::value << "\n";
}
Replace,
enum{value};
with,
static int const value; // or unsigned int
enums are must because they suppose to be resolved at compile time. Which assures that whatever result you calculated must have been done at compile time. Other such type is static int const (means any integral type).
To illustrate:
enum E {
X = strlen(s); // is an error, because X is a compile time constant
};
Alternatively, you can use static const members:
template <unsigned int n>
struct fact { static const unsigned int value = n * fact<n-1>::value; }

advice for static template class

I have this problem (histogramming). I've a real space: [a,b] partitioned in some way ([a0=a, a1, a2, ..., b]). The partitioning may be with equal space (a1 - a0 = a2 - a1 = ...) or variables.
I need a class that handle this, with some methods to say given a value in which bin of the partition it belongs; other methods to find the center of a particular bin and more.
During the program I don't like to instantiate a class only to call these simple function like
Binner binner(binning);
binner.get_bin(1.3);
binner.get_centerbin(2);
so I tried to write a static class using template to do something like that:
Binner<binning>::get_bin(1.3);
Binner<binning>::get_centerbin(2);
is it a good idea? There are other way to do it? Now I've free functions like
double get_bin(double bin, Binning binning); // a lot of if/else inside
but I think it's too error prone.
Here my implementation:
enum Binning {CELL, LARGE, BE};
const double binning_LARGE[] = {0, 1.2, 1.425, 1.550, 1.800, 2.5};
const double binning_BE[] = {0, 1.425, 1.550, 2.5};
template<Binning binning>
class Binner
{
public:
static const double* bins;
static const int n;
static int get_bin(double value);
};
template<> const double* myclass<LARGE>::bins = binning_LARGE;
template<> const double* myclass<BE>::bins = binning_BE;
template<> const int myclass<LARGE>::n = sizeof(binning_LARGE) / sizeof(double);
template<> const int myclass<BE>::n = sizeof(binning_BE) / sizeof(double);
template<Binning binning> int myclass<binning>::get_bin(double value)
{
return find_if(bins, bins + n,
bind2nd(greater<double>(), value)) - bins - 1;
}
template<> int myclass<CELL>::get_bin(double value)
{
return static_cast<int>(value / 0.025);
}
is it a good implementation / design?
Is there a way to avoid the n field using std::vector? How?
Is there a way to parametrize the 0.025? I know that double can't be template parameter but can I write something similar to this:
Binner<0.025> binner;
other / advices?
Edit:
For the third point Why I can't do that:
template<Binning binning, int N=100>
class Binner
{
public:
static const double* bins;
static const int n;
static int bin(double value);
};
...
template<Binning binning, int N> int Binner<CELL, N>::bin(double value)
{
return static_cast<int>(value / (2.5 / N));
}
IMHO, your design is ok, if you do not want to instantiate a class. Indeed, it seems a kind of template metaprogramming to me. Whether this makes sense depends on how you are planning to reuse this template.
Using a std::vector would allow you to get rid of the variable to hold the array size, for sure. Now, if this is good for your design, I don't know... it would move some complexity out of your template definition, to the binning definition (which now you can initialize very simply)...
Finally, you can instantiate your template passing a constant to it:
template < Binning binning, unsigned long N, unsigned long M>
class ... {
<using N>
}
have you considered a traits class? Typically if you have static information that you want to separate from the behaviour in a class, you might consider creating a traits class that encapsulates that.
So I'd start with the default behaviour:
enum Binning {CELL, LARGE, BE};
template <Binning binning>
struct BinTraits
{
// default behaviour
int get_bin(double value) { return value / 0.025; }
};
Then I'd provide the specialisations:
const double binning_LARGE[] = {0, 1.2, 1.425, 1.550, 1.800, 2.5};
const double binning_BE[] = {0, 1.425, 1.550, 2.5};
template <typename RandomAccessCollectionT>
int get_bin_impl(double value, RandomAccessCollectionT collection, unsigned size)
{
return find_if(collection, collection + size,
bind2nd(greater<double>(), value)) - collection - 1;
}
template <>
struct BinTraits<LARGE>
{
int get_bin(double value) { return get_bin_impl(value, binning_LARGE, sizeof(binning_LARGE) / sizeof(binning_LARGE[0])); }
};
template <>
struct BinTraits<BE>
{
int get_bin(double value) { return get_bin_impl(value, binning_BE, sizeof(binning_BE) / sizeof(binning_BE[0])); }
};
Then I'd put the actual container behaviour in another class that requires binning behaviour (lets call it HashTable):
template <typename BinTraits>
class HashTable
{
public:
void insert(double value)
{
int bin = BinTraits::get_bin(value);
_bins[bin].insert(value);
}
// _bin is a multimap or something
};
Looking at the usage of find_if and bind2nd as well as functors, it seems as if you are quite knowledgeable about STL and some advanced C++ concepts; yet, what you are trying to do seems to be over-engineering. While I can't fully understand what you are trying to do but it seems that you could do away with templates completely and use just a class (instantiated with different values) and method parameters.