This code is giving me incomplete type error.
What is the problem? Isn't allowed for a class to have static member instances of itself?
Is there a way to achieve the same result?
struct Size
{
const unsigned int width;
const unsigned int height;
static constexpr Size big = { 480, 240 };
static constexpr Size small = { 210, 170 };
private:
Size( ) = default;
};
A class is allowed to have a static member of the same type. However, a class is incomplete until the end of its definition, and an object cannot be defined with incomplete type. You can declare an object with incomplete type, and define it later where it is complete (outside the class).
struct Size
{
const unsigned int width;
const unsigned int height;
static const Size big;
static const Size small;
private:
Size( ) = default;
};
const Size Size::big = { 480, 240 };
const Size Size::small = { 210, 170 };
see this here: http://coliru.stacked-crooked.com/a/f43395e5d08a3952
This doesn't work for constexpr members, however.
Is there a way to achieve the same result?
By "the same result", do you specifically intend the constexpr-ness of
Size::big and Size::small? In that case maybe this would be close enough:
struct Size
{
const unsigned int width = 0;
const unsigned int height = 0;
static constexpr Size big() {
return Size { 480, 240 };
}
static constexpr Size small() {
return Size { 210, 170 };
}
private:
constexpr Size() = default;
constexpr Size(int w, int h )
: width(w),height(h){}
};
static_assert(Size::big().width == 480,"");
static_assert(Size::small().height == 170,"");
As a workaround you can use a separate base class which definition is complete when defining the constants in the derived class.
struct size_impl
{
//data members and functions here
unsigned int width;
unsigned int height;
};
struct size: public size_impl
{
//create the constants as instantiations of size_impl
static constexpr size_impl big{480,240};
static constexpr size_impl small{210,170};
//provide implicit conversion constructor and assignment operator
constexpr size(const size_impl& s):size_impl(s){}
using size_impl::operator=;
//put all other constructors here
};
//test:
constexpr size a = size::big;
You can put the base class in a separate namespace to hide its definition if you want to.
The code compiles with clang and gcc
Related
I have the following template class definition: a typical Matrix class -
template<typename T>
class Matrix
{
std::vector<Array<T>> m_rows;
uint32_t m_M;
uint32_t m_N;
bool m_container;
public:
Matrix() : m_rows{}, m_M(0), m_N(0), m_container(true) { }
Matrix(uint32_t width, uint32_t height, T val, uint32_t strideX=0, uint32_t strideY=0) :
m_rows(std::max(strideY, height), Array<T>(width, T{}, strideX)),
m_M(width), m_N(height), m_container(false)
{
for(uint32_t row=0; row < height; row++)
{
m_rows[row] = val;
}
}
//more class methods, not relevant to this discussion
Code in main():
int main()
{
typedef struct { float a; float b; } MyStruct;
MyStruct val = { 1.0, 2.0 };
Matrix<MyStruct> m(3,3,val); //so, define a 3x3 matrix with 'val' struct as constant value
}
The Matrix will try to initialize the std::vector<> container with T{} entries.
To my surprise, this worked! So, my next question is, WHY does T{} work? Is this the C++ way to 'cast' literals to the 'T' type, even if 'T' is composite?
thanks, Charles
It's because you are using MyStruct only. Since MyStruct can be initialized with {}, it can be compiled.
But if you have other classes that cannot be initialized with a default constructor, it can't be compiled.
struct foo{};
class faa{
public:
fee(int x){}
};
In this case,
Matrix<foo>
can be compiled, while
Matrix<faa>
cannot.
well i cant find how do this, basically its a variable union with params, basic idea, (writed as function)
Ex1
union Some (int le)
{
int i[le];
float f[le];
};
Ex2
union Some
{
int le;
int i[le];
float f[le];
};
obs this don't works D:
maybe a way to use an internal variable to set the lenght but don't works too.
Thx.
No, this is not possible: le would need to be known at compile-time.
One solution would be to use a templated union:
template <int N> union Some
{
int i[N];
float f[N];
};
N, of course, is compile-time evaluable.
Another solution is the arguably more succinct
typedef std::vector<std::pair<int, float>> Some;
or a similar solution based on std::array.
Depending on your use case you could try to simulate a union.
struct Some
{
//Order is important
private:
char* pData;
public:
int* const i;
float* const f;
public:
Some(size_t len)
:pData(new char[sizeof(int) < sizeof(float) ? sizeof(float) : sizeof(int)])
,i ((int*)pData)
,f ((float*)pData)
{
}
~Some()
{
delete[] pData;
}
Some(const Some&) = delete;
Some& operator=(const Some&) = delete;
};
Alternative solution using templates, unique_ptr and explicit casts:
//max_size_of<>: a recursive template struct to evaluate the
// maximum value of the sizeof function of all types passed as
// parameter
//The recursion is done by using the "value" of another
// specialization of max_size_of<> with less parameter types
template <typename T, typename...Args>
struct max_size_of
{
static const std::size_t value = std::max(sizeof(T), max_size_of<Args...>::value);
};
//Specialication for max_size_of<> as recursion stop
template <typename T>
struct max_size_of<T>
{
static const std::size_t value = sizeof(T);
};
//dataptr_auto_cast<>: a recursive template struct that
// introduces a virtual function "char* const data_ptr()"
// and an additional explicit cast operator for a pointer
// of the first type. Due to the recursion a cast operator
// for every type passed to the struct is created.
//Attention: types are not allowed to be duplicate
//The recursion is done by inheriting from of another
// specialization of dataptr_auto_cast<> with less parameter types
template <typename T, typename...Args>
struct dataptr_auto_cast : public dataptr_auto_cast<Args...>
{
virtual char* const data_ptr() const = 0; //This is needed by the cast operator
explicit operator T* const() const { return (T*)data_ptr(); } //make it explicit to avoid unwanted side effects (manual cast needed)
};
//Specialization of dataptr_auto_cast<> as recursion stop
template <typename T>
struct dataptr_auto_cast<T>
{
virtual char* const data_ptr() const = 0;
explicit operator T* const() const { return (T*)data_ptr(); }
};
//union_array<>: inherits from dataptr_auto_cast<> with the same
// template parameters. Also has a static const member "blockSize"
// that indicates the size of the largest datatype passed as parameter
// "blockSize" is used to determine the space needed to store "size"
// elements.
template <typename...Args>
struct union_array : public dataptr_auto_cast<Args...>
{
static const size_t blockSize = max_size_of<Args...>::value;
private:
std::unique_ptr<char[]> m_pData; //std::unique_ptr automatically deletes the memory it points to on destruction
size_t m_size; //The size/no. of elements
public:
//Create a new array to store "size" elements
union_array(size_t size)
:m_pData(new char[size*blockSize])
,m_size(size)
{
}
//Copy constructor
union_array(const union_array<Args...>& other)
:m_pData(new char[other.m_size*blockSize])
,m_size(other.m_size)
{
memcpy(m_pData.get(), other.m_pData.get(), other.m_size);
}
//Move constructor
union_array(union_array<Args...>&& other)
:m_pData(std::move(other.m_pData))
,m_size(std::move(other.m_size))
{
}
union_array& operator=(const union_array<Args...>& other)
{
m_pData = new char[other.m_size*blockSize];
m_size = other.m_size;
memcpy(m_pData.get(), other.m_pData.get(), other.m_size);
}
union_array& operator=(union_array<Args...>&& other)
{
m_pData = std::move(other.m_pData);
m_size = std::move(other.m_size);
}
~union_array() = default;
size_t size() const
{
return m_size;
}
//Implementation of dataptr_auto_cast<>::data_ptr
virtual char* const data_ptr() const override
{
return m_pData.get();
}
};
int main()
{
auto a = union_array<int, char, float, double>(5); //Create a new union_array object with enough space to store either 5 int, 5 char, 5 float or 5 double values.
((int*)a)[3] = 3; //Use as int array
auto b = a; //copy
((int*)b)[3] = 1; //Change a value
auto c = std::move(a);// move a to c, a is invalid beyond this point
// std::cout << ((int*)a)[3] << std::endl; //This will crash as a is invalid due to the move
std::cout << ((int*)b)[3] << std::endl; //prints "1"
std::cout << ((int*)c)[3] << std::endl; //prints "3"
}
Explanation
template <typename T, typename...Args>
struct max_size_of
{
static const std::size_t value = std::max(sizeof(T), max_size_of<Args...>::value);
};
template <typename T>
struct max_size_of<T>
{
static const std::size_t value = sizeof(T);
};
max_size_of<> is used to get the largest sizeof() value of all types passed as template paremeters.
Let's have a look at the simple case first.
- max_size_of<char>::value: value will be set to sizeof(char).
- max_size_of<int>::value: value will be set to sizeof(int).
- and so on
If you put in more than one type it will evaluate to the maximum of the sizeof of these types.
For 2 types this would look like this: max_size_of<char, int>::value: value will be set to std::max(sizeof(char), max_size_of<int>::value).
As described above max_size_of<int>::value is the same as sizeof(int), so max_size_of<char, int>::value is the same as std::max(sizeof(char), sizeof(int)) which is the same as sizeof(int).
template <typename T, typename...Args>
struct dataptr_auto_cast : public dataptr_auto_cast<Args...>
{
virtual char* const data_ptr() const = 0;
explicit operator T* const() const { return (T*)data_ptr(); }
};
template <typename T>
struct dataptr_auto_cast<T>
{
virtual char* const data_ptr() const = 0;
explicit operator T* const() const { return (T*)data_ptr(); }
};
dataptr_auto_cast<> is what we use as a simple abstract base class.
It forces us to implement a function char* const data_ptr() const in the final class (which will be union_array).
Let's just assume that the class is not abstract and use the simple version dataptr_auto_cast<T>:
The class implements a operator function that returns a pointer of the type of the passed template parameter.
dataptr_auto_cast<int> has a function explicit operator int* const() const;
The function provides access to data provided by the derived class through the data_ptr()function and casts it to type T* const.
The const is so that the pointer isn't altered accidentially and the explicit keyword is used to avoid unwanted implicit casts.
As you can see there are 2 versions of dataptr_auto_cast<>. One with 1 template paremeter (which we just looked at) and one with multiple template paremeters.
The definition is quite similar with the exception that the multiple parameters one inherits dataptr_auto_cast with one (the first) template parameter less.
So dataptr_auto_cast<int, char> has a function explicit operator int* const() const; and inherits dataptr_auto_cast<char> which has a function explicit operator char* const() const;.
As you can see there is one cast operator function implemented with each type you pass.
There is only one exception and that is passing the same template parameter twice.
This would lead in the same operator function being defined twice within the same class which doesn't work.
For this use case, using this as a base class for the union_array, this shouldn't matter.
Now that these two are clear let's look at the actual code for union_array:
template <typename...Args>
struct union_array : public dataptr_auto_cast<Args...>
{
static const size_t blockSize = max_size_of<Args...>::value;
private:
std::unique_ptr<char[]> m_pData;
size_t m_size;
public:
//Create a new array to store "size" elements
union_array(size_t size)
:m_pData(new char[size*blockSize])
,m_size(size)
{
}
//Copy constructor
union_array(const union_array<Args...>& other)
:m_pData(new char[other.m_size*blockSize])
,m_size(other.m_size)
{
memcpy(m_pData.get(), other.m_pData.get(), other.m_size);
}
//Move constructor
union_array(union_array<Args...>&& other)
:m_pData(std::move(other.m_pData))
,m_size(std::move(other.m_size))
{
}
union_array& operator=(const union_array<Args...>& other)
{
m_pData = new char[other.m_size*blockSize];
m_size = other.m_size;
memcpy(m_pData.get(), other.m_pData.get(), other.m_size);
}
union_array& operator=(union_array<Args...>&& other)
{
m_pData = std::move(other.m_pData);
m_size = std::move(other.m_size);
}
~union_array() = default;
size_t size() const
{
return m_size;
}
virtual char* const data_ptr() const override
{
return m_pData.get();
}
};
As you can see union_array<> inherits from dataptr_auto_cast<> using the same template arguments.
So this gives us a cast operator for every type passed as template paremeter to union_array<>.
Also at the end of union_array<> you can see that the char* const data_ptr() const function is implemented (the abstract function from dataptr_auto_cast<>).
The next interesting thing to see is static const size_t blockSize which is initilialized with the maximum sizeof value of the template paremeters to union_array<>.
To get this value the max_size_of is used as described above.
The class uses std::unique_ptr<char[]> as data storage, as std::unique_ptr automatically will delete the space for us, once the class is destroyed.
Also std::unique_ptr is capable of move semantics, which is used in the move assign operator function and the move constructor.
A "normal" copy assign operator function and a copy constructor are also included and copy the memory accordingly.
The class has a constructor union_array(size_t size) which takes the number of elements the union_array should be able to hold.
Multiplying this value with blockSize gives us the space needed to store exactly size elements of the largest template type.
Last but not least there is an access method to ask for the size() if needed.
C++ requires that the size of a type be known at compile time.
The size of a block of data need not be known, but all types have known sizes.
There are three ways around it.
I'll ignore the union part for now. Imagine if you wanted:
struct some (int how_many) {
int data[how_many];
};
as the union part adds complexity which can be dealt with separately.
First, instead of storing the data as part of the type, you can store pointers/references/etc to the data.
struct some {
std::vector<int> data;
explicit some( size_t how_many ):data(how_many) {};
some( some&& ) = default;
some& operator=( some&& ) = default;
some( some const& ) = default;
some& operator=( some const& ) = default;
some() = default;
~some() = default;
};
here we store the data in a std::vector -- a dynamic array. We default copy/move/construct/destruct operations (explicitly -- because it makes it clearer), and the right thing happens.
Instead of a vector we can use a unique_ptr:
struct some {
std::unique_ptr<int[]> data;
explicit some( size_t how_many ):data(new int[how_many]) {};
some( some&& ) = default;
some& operator=( some&& ) = default;
some() = default;
~some() = default;
};
this blocks copying of the structure, but the structure goes from being size of 3 pointers to being size of 1 in a typical std implementation. We lose the ability to easily resize after the fact, and copy without writing the code ourselves.
The next approach is to template it.
template<std::size_t N>
struct some {
int data[N];
};
this, however, requires that the size of the structure be known at compile-time, and some<2> and some<3> are 'unrelated types' (barring template pattern matching). So it has downsides.
A final approach is C-like. Here we rely on the fact that data can be variable in size, even if types are not.
struct some {
int data[1]; // or `0` in some compilers as an extension
};
some* make_some( std::size_t n ) {
Assert(n >= 1); // unless we did `data[0]` above
char* buff = new some[(n-1)*sizeof(int) + sizeof(some)]; // note: alignment issues on some platforms?
return new(buff) some(); // placement new
};
where we allocate a buffer for some of variable size. Access to the buffer via data[13] is practically legal, and probably actually so as well.
This technique is used in C to create structures of variable size.
For the union part, you'll want to create a buffer of char with the right size std::max(sizeof(float), sizeof(int))*N, and expose functions:
char* data(); // returns a pointer to the start of the buffer
int* i() { return reinterpret_cast<int*>(data()); }
float* f() { return reinterpret_cast<float*>(data()); }
you may also need to properly initialize the data as the proper type; in theory, a char buffer of '\0's may not correspond to defined float values or ints that are zero.
I would like to suggest a different approach: Instead of tying the number of elements to the union, tie it outside:
union Some
{
int i;
float f;
};
Some *get_Some(int le) { return new Some[le]; }
Don't forget to delete[] the return value of get_Some... Or use smart pointers:
std::unique_ptr<Some[]> get_Some(int le)
{ return std::make_unique<Some[]>(le); }
You can even create a Some_Manager:
struct Some_Manager
{
union Some
{
int i;
float f;
};
Some_Manager(int le) :
m_le{le},
m_some{std::make_unique<Some[]>(le)}
{}
// ... getters and setters...
int count() const { return m_le; }
Some &operator[](int le) { return m_some[le]; }
private:
int m_le{};
std::unique_ptr<Some[]> m_some;
};
Take a look at the Live example.
It's not possible to declare a structure with dynamic sizes as you are trying to do, the size must be specified at run time or you will have to use higher-level abstractions to manage a dynamic pool of memory at run time.
Also, in your second example, you include le in the union. If what you were trying to do were possible, it would cause le to overlap with the first value of i and f.
As was mentioned before, you could do this with templating if the size is known at compile time:
#include <cstdlib>
template<size_t Sz>
union U {
int i[Sz];
float f[Sz];
};
int main() {
U<30> u;
u.i[0] = 0;
u.f[1] = 1.0;
}
http://ideone.com/gG9egD
If you want dynamic size, you're beginning to reach the realm where it would be better to use something like std::vector.
#include <vector>
#include <iostream>
union U {
int i;
float f;
};
int main() {
std::vector<U> vec;
vec.resize(32);
vec[0].i = 0;
vec[1].f = 42.0;
// But there is no way to tell whether a given element is
// supposed to be an int or a float:
// vec[1] was populated via the 'f' option of the union:
std::cout << "vec[1].i = " << vec[1].i << '\n';
}
http://ideone.com/gjTCuZ
Since C++11, one can initialize static const built-in types inside a class definition, like so:
class A {
public:
static const unsigned int val = 0; //allowed
};
However, doing this in Visual C++ 2013 with an array gives me an error telling me that this is not allowed:
class B {
public:
static const unsigned int val[][2] = { { 0, 1 } }; //not allowed
};
The error message simply reads "a member of type const unsigned int [][2] cannot have an in-class initializer." Instead, I'm forced to do the following:
class C {
public:
static const unsigned int val[][2];
};
const unsigned int C::val[][2] = { { 0, 1 } };
This is unfortunate because I have code which relies on the size of val, and I want to be able to change the contents of val without having to remember to go back and change a constant somewhere. Is there a different way of doing this that allows me to use sizeof on val from any point in the file below the declaration?
Your array must be a constexpr (clang and gcc specify it in their error messages) :
class B {
public:
static constexpr const unsigned int val[][2] = { { 0, 1 } };
// ^^^^^^^^
};
See it working here.
Visual Studio CTP 2013 (a "beta" version, that should be avoided for production) provides support for constepxr, which should be available in future releases, too.
EDIT :
If your compiler does not support constexpr (hopefully for you, not for too long), then you cant do in-class initialization of your static array, and must do the old way :
class C {
public:
static const unsigned int val[][2];
};
const unsigned int C::val[][2] = { { 0, 1 } };
If your array type is complete (if you declare all the array dimensions), then sizeof can be applied (the compiler knows how many elements to expect) :
;
class C {
public:
static const unsigned int val[2][2]; // Specify all dimensions.
void foo() { cout << sizeof(C::val); } // OK
};
const unsigned int C::val[][2] = { { 0, 1 } , { 2, 3 } };
int main() {
C c;
c.foo();
return 0;
}
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;
};
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;
};