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;
};
Related
I'm working with a variable-width communications format. The structs to handle it look something like this:
struct Header
{
int msgType = -1, len;
Header() { len = sizeof(*this); }
};
struct A : public Header
{
int x; char y;
A() { msgType = 1; len = sizeof(*this); }
};
// Further structs B, C, ... declared along the same lines
I would like to have a constexpr static member Header::MAX_SIZE which gives the max size of any of these derived classes, e.g. so I can allocate a buffer which is guaranteed to hold any such packet. So I'd like to do something like
struct Header
{
int msgType = -1, len;
constexpr static std::size_t MAX_SIZE;
Header() { len = sizeof(*this); }
};
// ... declaration of subclasses ...
inline Header::MAX_SIZE = std::max({ sizeof(A), sizeof(B), sizeof(C) });
I need the definition to come outside of the class because it depends on sizeof(A), etc., which in turn depend on the definition of Header.
It seems like this sort of thing should be unobjectionable: I'm giving the definition of the member in the same source file, and it can be computed at compile time. But I haven't found any way to tell the compiler to actually do this.
constexpr goes on the initializing declaration of a variable, so just put it outside the class:
struct Header
{
int msgType = -1, len;
static const std::size_t MAX_SIZE;
Header() { len = sizeof(*this); }
};
// ... declaration of subclasses ...
inline constexpr std::size_t Header::MAX_SIZE = std::max({ sizeof(A), sizeof(B), sizeof(C) });
Note that the implicit const must be spelled out in the declaration. The definition should go in the same header to avoid any translation unit seeing the declaration but not the inline, which is not allowed.
I have a class with a member function which declares an array whose size is based off a formula.
template <int SIZE>
class Example{
constexpr int lookup(const int n) const
{
return n * n + n;
}
inline void func()
{
double array[lookup(SIZE)];
}
};
This gives me the vla error. I think it should work because SIZE is resolved at compile time, and lookup is a constexpr. I know the following will work:
template <int SIZE>
class Example{
inline void func()
{
constexpr int sz = SIZE * SIZE + SIZE;
double array[sz];
}
};
I guess I'm just trying to figure out why
EDIT Sorry for the typos, was trying to just write a smaller example and ended up with the missing n and class name.
It's complicated...
First of all, some compilers (see MikeCAT answer and Bill Lynch linked example) can compile the following code (if you give a name to the class and correct lookup() naming n the argument)
inline void func()
{
double array[lookup(SIZE)];
}
because they support a C99 extension that accept the "variable length array" feature.
But this extension isn't standard C++.
You can verify this modifying func() as follows (almost equivalent, in standard C++)
inline void func()
{
constexpr int s = lookup(SIZE);
double array[s];
}
and this can't compile if lookup() is a non-static method
Consider that
lookup(SIZE);
is a short form for
this->lookup(SIZE);
I mean... the use of lookup() involve an object of your class.
The problem is that your func() method is available for both constexpr and non-constexpr objects.
Suppose you have a non-constexpr object: calling func() from it you impose that
constexpr int s = this->lookup(SIZE);
is evaluated compile-time.
That is: you impose that the this pointer (so the object itself) is available compile-time.
This is clearly impossible for run-time created objects, so your code can't compile.
Different if you declare lookup() as a static method: this way, calling lookup() doesn't involve an object of your class so your code can compile.
Class template must have a name.
n is not declared in lookup.
This should work as C++11:
template <int SIZE>
class hoge { // add hoge
constexpr int lookup(const int n) const // add n
{
return n * n + n;
}
inline void func()
{
double array[lookup(SIZE)];
}
};
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 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.
If I have a class that defines multiple constant variables like so...
class SomeClass {
public:
SomeClass() : SOME_CONSTANT(20), ANOTHER_CONSTANT(45), ANOTHER_CONSTANT2(25), ANOTHER_CONSTANT2(93) { }
private:
const int SOME_CONSTANT;
const int ANOTHER_CONSTANT;
const int ANOTHER_CONSTANT2;
const int ANOTHER_CONSTANT3;
Will multiple instances of this class be optimized to point to the same memory for the constants? or can I save memory by making each constant static?
If they are not static, then no, they will not be optimized out. Each instance will have space for all the constants. (In fact, I don't think the compiler is even allowed to combine them in any way.)
If you do declare them static, they are in global memory and not in each instance. So yes, it will use less memory.
EDIT:
If you want to make them static constants, it should be done like this:
class SomeClass {
public:
SomeClass(){ }
private:
static const int SOME_CONSTANT;
static const int ANOTHER_CONSTANT;
static const int ANOTHER_CONSTANT2;
static const int ANOTHER_CONSTANT3;
};
const int SomeClass::SOME_CONSTANT = 20;
const int SomeClass::ANOTHER_CONSTANT = 45;
const int SomeClass::ANOTHER_CONSTANT2 = 25;
const int SomeClass::ANOTHER_CONSTANT3 = 93;
How about an enumeration instead?
class SomeClass {
public:
SomeClass() { }
private:
enum {
SOME_CONSTANT = 20,
ANOTHER_CONSTANT = 45,
ANOTHER_CONSTANT2 = 25,
ANOTHER_CONSTANT3 = 93
};
};
An enumeration guarantees that the constants won't take up any memory at all.
Declared this way, all instances of this class will have its own copies. To avoid this and save memory, declare them as static.
Note: don't forget to define them outside the class. As these are ints, you may avoid defining them outside the class, this actually depends more on the compiler, than the standard (yes, I know how ridiculous this soudns). I can't test it now, but I remember, that gcc and VS have different behaviors about this.
So, you may need to do this:
class SomeClass {
public:
SomeClass()
{ }
private:
static const int SOME_CONSTANT;
static const int ANOTHER_CONSTANT;
static const int ANOTHER_CONSTANT2;
static const int ANOTHER_CONSTANT3;
const int SomeClass::SOME_CONSTANT = 20;
//.. the same for the others.
EDIT I'll find this part of the standard (the exception for integral types) and post it here + tests on both compilers later today :) )
You cannot make those constants static - simply because your constructor initialses them!
SomeClass() : SOME_CONSTANT(20), ANOTHER_CONSTANT(45), ANOTHER_CONSTANT2(25), ANOTHER_CONSTANT2(93) { }
Remove those initialisers i.e.
SomeClass{};
static const int SOME_CONSTANT = 20;
Then you will have just one int for the class.
You can try checking the sizeof() of an instance of the class. I don't think they'll be optimized out. Using const static variables for this purpose will probably be the right thing to do, especially if they are all integers, in which case you can initialize them at the definition and get compile time constants without worrying about static objects initialization order.
class SomeClass
{
private:
const static int SOME_CONSTANT = 20;
const static int ANOTHER_CONSTANT = 45;
const static int ANOTHER_CONSTANT2 = 25;
const static int ANOTHER_CONSTANT3 = 93;
};