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.
Related
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?
I'm working on trying to get a Linux based project, written in C++17 to work on OSX (Mojave). Most everything compiles just fine, until I get to this file: ClassName.hpp:
class ClassName {
public:
static constexpr double DEFAULT_TARGET_TINITIAL_DIGITS_FROM_1 = 2; // represents 0.99
static constexpr double DEFAULT_TARGET_TFINAL_DIGITS_FROM_0 = 10; // represents 1e-10
static constexpr double DEFAULT_TARGET_INITIAL_PBAD = (1-pow(10,-DEFAULT_TARGET_TINITIAL_DIGITS_FROM_1));
static constexpr double DEFAULT_TARGET_FINAL_PBAD = pow(10,-DEFAULT_TARGET_TFINAL_DIGITS_FROM_0);
static constexpr double DEFAULT_ERROR_TOL_DIGITS = 0.9; // as a fraction of digits in the last place from the above.
static constexpr double DEFAULT_SAMPLE_TIME = 1;
// more unrelated code
};
When compiling this I get the following error:
error: constexpr variable
'DEFAULT_TARGET_INITIAL_PBAD' must be initialized by a constant expression
...double DEFAULT_TARGET_INITIAL_PBAD = (1-pow(10,-DEFAULT_TARGET_TINITIAL_DIGITS_FROM_1));
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ClassName.hpp: note: non-constexpr function 'pow<int, double>'
cannot be used in a constant expression
static constexpr double DEFAULT_TARGET_INITIAL_PBAD = (1-pow(10,-DEFAULT_TARGET_TINITI...
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/math.h:968:1: note:
declared here
pow(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT
So for some reason this works on Ubuntu and CentOS. I think it has to do with how pow is defined? But I'm not sure how to fix it, or if that is even the issue. I've also tried removing constexpr from DEFAULT_TARGET_TINITIAL_DIGITS_FROM_1 and DEFAULT_TARGET_TFINAL_DIGITS_FROM_0 and making them const but still run into the same issue.
First, you can't initialize constexpr class members with functions that aren't constexpr and std::pow isn't constepxr in standard C++17 . The workaround is to declare them const. While they can't be used in places that require a compile time const they are immutable. A traditional approach is declaring them in header which you include as needed in source files. Then you hneed one implementation file that defines the static const members.
If your code requires compile time const's or constexpr your only option is to write your own pow.
Here's one way to initialize const statics with functions that are not constexpr prior to executing the main() using a portion of your question that shows the technique:
Create a header, constinit.h, that declares the class
// include header guards
// declare the static consts
struct ClassName {
static double DEFAULT_TARGET_TINITIAL_DIGITS_FROM_1; // represents 0.99
static double DEFAULT_TARGET_INITIAL_PBAD; // to be initialized by pow
};
Create an implementation file that initializes the statics:
#include "constinit.h"
#include <cmath>
double ClassName::DEFAULT_TARGET_TINITIAL_DIGITS_FROM_1{ 2 }; // represents 0.99
double ClassName::DEFAULT_TARGET_INITIAL_PBAD = (1 - std::pow(10, -DEFAULT_TARGET_TINITIAL_DIGITS_FROM_1));
To use the statics:
#include <iostream>
#include "constinit.h"
int main()
{
std::cout << ClassName::DEFAULT_TARGET_INITIAL_PBAD << std::endl;
}
If constexpr for compile time initialization is required you need to define your own constexpr pow function. This works in C++17:
#pragma once // or header guards per your preference
constexpr double my_pow(double x, int exp)
{
int sign = 1;
if (exp < 0)
{
sign = -1;
exp = -exp;
}
if (exp == 0)
return x < 0 ? -1.0 : 1.0;
double ret = x;
while (--exp)
ret *= x;
return sign > 0 ? ret : 1.0/ret;
}
class ClassName {
public:
static constexpr double DEFAULT_TARGET_TINITIAL_DIGITS_FROM_1 = 2; // represents 0.99
static constexpr double DEFAULT_TARGET_TFINAL_DIGITS_FROM_0 = 10; // represents 1e-10
static constexpr double DEFAULT_TARGET_INITIAL_PBAD = (1 - my_pow(10, -DEFAULT_TARGET_TINITIAL_DIGITS_FROM_1));
static constexpr double DEFAULT_TARGET_FINAL_PBAD = my_pow(10, -DEFAULT_TARGET_TFINAL_DIGITS_FROM_0);
static constexpr double DEFAULT_ERROR_TOL_DIGITS = 0.9; // as a fraction of digits in the last place from the above.
static constexpr double DEFAULT_SAMPLE_TIME = 1;
// more unrelated code
};
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.
I'm trying to use a class to group all the parameters of a template data structure, in particular an intrusive AVL tree. The user would do something like this:
struct MyEntry {
MyEntry *parent;
MyEntry *child[2];
int balance;
int value;
};
struct MyAvlTreeParams {
typedef MyEntry entry_type;
static constexpr auto parent_member = &MyEntry::parent;
static constexpr auto child_member = &MyEntry::child;
static constexpr auto balance_member = &MyEntry::balance;
... // comparators also come here which compare MyEntry::value
};
AvlTree<MyAvlTreeParams> tree;
MyEntry entry1, entry2;
entry1.value = 6;
entry2.value = 8;
tree.insert(&entry1);
tree.insert(&entry2);
But there is a problem with the member pointers in MyAvlTreeParams. This sample demonstrates it:
struct A {
int x;
};
struct B {
static constexpr auto member = &A::x;
};
int main ()
{
A a;
(a.*(B::member)) = 6;
return 0;
}
This works with clang++ 3.1, but g++ 4.7.2 fails to link with the error:
/tmp/ccGXGIOl.o:a.cpp:function main: error: undefined reference to 'B::member'
The error is fixed by adding the following declaration some place after the definition of struct B (see this question):
constexpr int (A::*(B::member));
To see how this becomes problematic in my case, all the following would need to be added whenever the AVL tree is used:
constexpr MyEntry * MyEntry::*(MyAvlTreeParams::parent_member);
constexpr MyEntry * (MyEntry::*(MyAvlTreeParams::child_member))[2];
constexpr int MyEntry::*(MyAvlTreeParams::balance_member);
Is there any way to do this without such information-less boilerplate code, or something different which achieves the same goals of grouping parameters (i.e. not just passing all the members as template parameters)?
So I just learned via a compiler error that in-class initialization of arrays is invalid (why?). Now I would like to have some arrays initialized in a template class, and unfortunatly the contents depend on the template parameter. A condensed testcase looks like this:
template<typename T>
struct A {
T x;
static const int len = sizeof(T); // this is of course fine
static const int table[4] = { 0, len, 2*len, 3*len }; //this not
}
Any idea how to pull out the constant array?
EDIT: Added the 'int's.
Just as you'd do it without templates; put the initialization outside the class' declaration:
template<class T>
const int A<T>::table[4] = { 0, len, 2*len, 3*len };
class Y
{
const int c3 = 7; // error: not static
static int c4 = 7; // error: not const static const
float c5 = 7; // error not integral
};
So why do these inconvenient restrictions exist? A class is typically declared in a header file and a header file is typically included into many translation units. However, to avoid complicated linker rules, C++ requires that every object has a unique definition. That rule would be broken if C++ allowed in-class definition of entities that needed to be stored in memory as objects.
for more detail read : How do I define an in-class constant?
template <typename T, int index>
struct Table {
static const len = sizeof(T);
static const value = len*index;
};