I'm fairly new to c++, and am trying to create a const pointer array to hold shortcuts to a few structures.
The issue I'm having is that C++03 (or the compiler I'm using - gcc 4.4.7) apparently doesn't support constant pointer arrays? Or at least you can't create them for existing objects?
To clarify, the pointers themselves are to be constant, but the objects they point to are variable. And the array structure is crucial because it greatly simplifies my code if I can access these objects by index later on.
This is for work with spacecraft hardware that has flight heritage or something, so it's not feasible to use a newer compiler :/
struct Type1 {
unsigned short thing1;
};
struct Type2 {
Type1 thing2;
};
struct Type3 {
Type2 thing3;
};
class A {
Type3 Array[4];
Type1 *const pArray[4] = {
&Array[0].thing3.thing2,
&Array[1].thing3.thing2,
&Array[2].thing3.thing2,
&Array[3].thing3.thing2
};
};
error: a brace-enclosed initializer is not allowed here before ‘{’ token
error: ISO C++ forbids initialization of member ‘pArray’
error: making ‘pArray’ static
error: invalid in-class initialization of static data member of non-integral type ‘MyType* const [4]’
So is it even possible to do what I'm trying to do given the compiler I'm using?
Because pArray is const, it requires an initializer. Because it is a non-static member variable, it can only be initialized from the initializer list of a constructor. Because it is an array, there is no syntax for this in C++03.
One possible workaround is to make it a non-array:
#include <cstddef>
struct Type1 {
unsigned short thing1;
};
struct Type2 {
Type1 thing2;
};
struct Type3 {
Type2 thing3;
};
class A {
struct xarray4 {
Type1 *data[4];
xarray4(Type1 *p0, Type1 *p1, Type1 *p2, Type1 *p3) {
data[0] = p0;
data[1] = p1;
data[2] = p2;
data[3] = p3;
}
Type1 *&operator[](std::size_t n) {
return data[n];
}
Type1 *const &operator[](std::size_t n) const {
return data[n];
}
};
Type3 Array[4];
const xarray4 pArray;
A() : pArray(
&Array[0].thing3.thing2,
&Array[1].thing3.thing2,
&Array[2].thing3.thing2,
&Array[3].thing3.thing2
) {
}
};
Here pArray is not an array, but an object with overloaded operator[]. Because it is an object, we can give it a custom constructor that lets us initialize it the way we want.
With the overloaded [] operator we can still access the pointers by index.
Related
I am trying to define a union struct with some struct and primitive members overlapping in memory with a simple array. This works perfectly in Clang and MSVC, but it doesn't compile with GCC (G++).
struct Vector3 {
float x;
float y;
float z;
Vector3() {}
};
struct Plane {
union {
struct {
Vector3 normal;
float d;
};
float elements[4] = { 0 };
};
Plane() {}
};
With GCC, I get this compile error:
<source>:11:33: error: member 'Vector3 Plane::<unnamed union>::<unnamed struct>::normal' with constructor not allowed in anonymous aggregate
11 | Vector3 normal;
| ^~~~~~
Is the code example I gave valid C++? Why specifically is it not allowed in an anonymous aggregate, but it seems to work in a named one? What can I change about it to make it work in GCC that doesn't involve deleting the constructors or naming the struct in the union? What is the reason that it works in Clang and MSVC but not in GCC?
Is there a way to make it work if I replace struct { with struct Named {?
Is the code example I gave valid C++?
No. Anonymous structs are not allowed, so the program is ill-formed.
What is the reason that it works in Clang and MSVC
When an ill-formed program works, it is often due to a language extension.
but not in GCC
Differences in implementation of similar language extension perhaps. The limitations of such extension are not defined by the language of course. Since this extension is based on a C language feature, it sort of makes sense that it doesn't necessarily work with C++ features such as constructors.
What can I change about it to make it work in GCC that doesn't involve deleting the constructors or naming the struct in the union?
Only way to make the program well defined C++ is to not use an anonymous struct.
Bonus answer: If you were hoping to read elements after having written to normal or d or vice versa, then that's not allowed either. The behaviour of the program would be undefined.
How can I make differently named properties with overlapping memory? Aside from Plane, I also want to do this in other structs, such as by having a 3D Basis struct columns[3] with the array's members also accessible via x, y, and z.
C++ is limited in this regard and it cannot be done in a simple way. It can be done with a bit of complexity by relying on operator overloads:
template<class T, std::size_t size, std::size_t i>
struct Pun {
T a[size];
static_assert(i < size);
auto& operator=(T f) { a[i] = f; return *this; }
operator T&() & { return a[i]; }
operator const T&() const & { return a[i]; }
operator T () && { return a[i]; }
T * operator&() & { return a+i ; }
T const* operator&() const & { return a+i ; }
};
template<class T, std::size_t size>
struct Pun<T, size, size> {
T a[size];
using A = T[size];
operator A&() & { return a; }
operator const A&() const & { return a; }
A * operator&() & { return &a; }
A const* operator&() const & { return &a; }
};
union Plane {
Pun<float, 4, 4> elements;
Pun<float, 4, 0> x;
Pun<float, 4, 1> y;
Pun<float, 4, 2> z;
Pun<float, 4, 3> d;
};
Reading inactive members of Plane is allowed, because all elements are layout compatible structs. x etc. can implicitly convert to float and elements can implicitly convert to an array of float.
Given an container such as a vector<int>
#include <vector>
using namespace std;
vector<int> v{1, 2, 3};
Why does it seem to be quite difficult to access the public type members such as iterator and const_iterator? As I understand it, these names are part of the class (not the object) and must be accessed via :: to specify the scope, but is there a reason to forbid v.const_iterator when v is known?
Example:
int f(v.iterator it) {
return *it;
}
// or
int g(v::iterator it) {
return *it;
}
A workaround would be using decltype as in:
int h(decltype(v)::iterator it) {
return *it;
}
But this approach does not even work in classes, as the following fails:
class A
{
public:
int h(decltype(x)::iterator it) {
return *it;
}
private:
vector<int> x;
};
Edit
Just a little sidenote.
As pointed out, the meaning of v.iterator would depend on the type of v at the point of usage (compile time) ignoring runtime polymorphism. But the same is true for static class members.
Example:
struct A
{
static const int x = 1;
};
struct B : public A
{
static const int x = 2;
};
void eval()
{
B b;
A& ar = b;
b.x; // 2
ar.x; // 1, even though ar refers to the same underlying object (by the base type)
}
As #Slava pointed out in comments, decltype(x) is the way to do it:
#include <vector>
using namespace std;
vector<int> v{1, 2, 3};
int f(decltype(v)::iterator it) {
return *it;
}
int g(decltype(v)::iterator it) {
return *it;
}
class A
{
private:
vector<int> x;
public:
int h(decltype(x)::iterator it) {
return *it;
}
};
The member access . operator and scope resolution operator :: may not be overloaded. And as you might deduce from the names, . is used to access members, while :: is used to access scope.
#include <iostream>
struct B {
class iterator { };
// no need for typename, compiler knows that we mean typedef B::iterator, as he can only find it
iterator iterator1;
// member named the same as class, ops!
int iterator;
// we need to use typename here, B::iterator is resolved as member
// iterator iteartor3;
typename B::iterator iterator2;
};
int main() {
B bobj;
// we access the member iterator inside b
bobj.iterator = 1;
// we declare object of B::iterator type
// we need to tell compiler that we want only types
typename B::iterator iterator;
// this will work too
typename decltype(bobj)::iterator iterator2;
// we declare a member pointer to the iterator member inside some B class
// no typename, as I want pointer to member, not pointer to... type
int B::* pointer = &B::iterator;
// this is just a pointer to the iterator specifically in bobj class
int * pointer2 = &bobj.iterator;
// foo(bar)
bobj.*pointer = 1;
// this will work as expected
int decltype(bobj)::* pointer3 = &B::iterator;
}
Also, there are no "type members" in C++ (at least I couldn't find them in C++ standard). Classes and enumerations and typedefs declarations declared in a class as members are called "nested types" or "nested classes".
Basically, C++ lets you get either values or types when you access them through ::. So MyType::AnotherType is fine as well as MyType::AValue. When you go through an instance with ., it only means it want to resolve a symbol which is a kind of a value (field, func, etc.). Hope that helps.
Can this structure MyWrapStruct:
struct MyWrapStruct
{
bool myBool;
union
{
struct
{
void* myPtr;
int myInt;
};
Struct1 myStruct1;
Struct2 myStruct2;
} myStructs;
};
With "sub-structures" :
struct Struct1
{
void* myPtr;
int myInt;
float mySpecialFloat;
};
struct Struct2
{
void* myPtr;
int myInt;
int mySpecialInt;
};
Be considered a POD structure?
Yes - even union types merely contains data, and no methods, constructors, etc.
See:
What are POD types in C++?
Update
Provided, of course, the union only contains POD types.
See:
Questions regarding C++ non-POD unions
I was trying to write a templated base class to store a fixed number of data types, each with varying length. Here is a simplified version of much what I was trying to do:
template< int NINT, int NR0 >
class EncapsulatedObjectBase
{
public:
EncapsulatedObjectBase();
~EncapsulatedObjectBase();
double m_real[NR0];
int m_int[NINT];
}
Yeah...so the template parameters can be zero, thus declaring a zero-length array of objects. There will be multiple derived classes for this base, each defining their own number of variables. I have two questions:
1) Is this approach fundamentally flawed?
2) If so...why doesn't icc13 or gcc4.7.2 give me warnings about this when I instantiate a zero-length array? For gcc I use -wall and -wextra -wabi. The lack of warnings made me think that this sort of thing was OK.
EDIT:
Here is the contents of a file that show what I am talking about:
#include <iostream>
template< int NINT, int NR0 >
class EncapsulatedObjectBase
{
public:
EncapsulatedObjectBase(){}
~EncapsulatedObjectBase(){}
double m_real[NR0];
int m_int[NINT];
};
class DerivedDataObject1 : public EncapsulatedObjectBase<2,0>
{
public:
DerivedDataObject1(){}
~DerivedDataObject1(){}
inline int& intvar1() { return this->m_int[0]; }
inline int& intvar2() { return this->m_int[1]; }
};
class DerivedDataObject2 : public EncapsulatedObjectBase<0,2>
{
public:
DerivedDataObject2(){}
~DerivedDataObject2(){}
inline double& realvar1() { return this->m_real[0]; }
inline double& realvar2() { return this->m_real[1]; }
};
int main()
{
DerivedDataObject1 obj1;
DerivedDataObject2 obj2;
obj1.intvar1() = 12;
obj1.intvar2() = 5;
obj2.realvar1() = 1.0e5;
obj2.realvar2() = 1.0e6;
std::cout<<"obj1.intvar1() = "<<obj1.intvar1()<<std::endl;
std::cout<<"obj1.intvar2() = "<<obj1.intvar2()<<std::endl;
std::cout<<"obj2.realvar1() = "<<obj2.realvar1()<<std::endl;
std::cout<<"obj2.realvar2() = "<<obj2.realvar2()<<std::endl;
}
If I compile this with "g++ -Wall -Wextra -Wabi main.cpp" I get no warnings. I have to use the -pedantic flag to get warnings. So I still don't know how unsafe this is. In retrospect, I feel as though it must not be a very good idea...although it would be pretty useful if I could get away with it.
Zero-sized arrays are actually illegal in C++:
[C++11: 8.3.4/1]: [..] If the constant-expression (5.19) is present, it shall be an integral constant expression and its value shall be greater than zero. The constant expression specifies the bound of (number of elements in) the array. If the value of the constant expression is N, the array has N elements numbered 0 to N-1, and the type of the identifier of D is “derived-declarator-type-list array of N T”. [..]
For this reason, your class template cannot be instantiated with arguments 0,0 in GCC 4.1.2 nor in GCC 4.7.2 with reasonable flags:
template< int NINT, int NR0 >
class EncapsulatedObjectBase
{
public:
EncapsulatedObjectBase();
~EncapsulatedObjectBase();
double m_real[NR0];
int m_int[NINT];
};
int main()
{
EncapsulatedObjectBase<0,0> obj;
}
t.cpp: In instantiation of 'EncapsulatedObjectBase<0, 0>':
t.cpp:17: instantiated from here
Line 10: error: ISO C++ forbids zero-size array
compilation terminated due to -Wfatal-errors.
clang 3.2 says:
source.cpp:10:17: warning: zero size arrays are an extension [-Wzero-length-array]
(Note that, in any case, you won't get any error until you do try to instantiate such a class.)
So, is it a good idea? No, not really. I'd recommend prohibiting instantiation for your class template when either argument is 0. I'd also look at why you want to have zero-length arrays and consider adjusting your design.
In C using a zero-sized array as the last member of a struct is actually legal and is commonly used when the struct is going to end up with some sort of dynamically-created inline data that's not known at compile-time. In other words, I might have something like
struct MyData {
size_t size;
char data[0];
};
struct MyData *newData(size_t size) {
struct MyData *myData = (struct MyData *)malloc(sizeof(struct MyData) + size);
myData->size = size;
bzero(myData->data, size);
return myData;
}
and now the myData->data field can be accessed as a pointer to the dynamically-sized data
That said, I don't know how applicable this technique is to C++. But it's probably fine as long as you never subclass your class.
1) Add to declaration of your class C++11 static_assert or BOOST_STATIC_ASSERT and you will have compile-time diagnostic for zero length array:
....
BOOST_STATIC_ASSERT(NR0 > 0);
BOOST_STATIC_ASSERT(NINT > 0);
double m_real[NR0];
int m_int[NINT];
};
2) Use std::array or boost::array and you will have run-time diagnostic (in debug mode) for index overflow problem in such code:
BOOST_STATIC_ASSERT(NR0 > 0);
BOOST_STATIC_ASSERT(NINT > 0);
boost::array<double, NR> m_real; //double m_real[NR0];
boost::array<int, NINT> m_int; //int m_int[NINT];
};
Remark:
class boost::array has specialisation for zero-size array
3) Use size_t but not int for size of array.
Your design is quite dangerous:
DerivedDataObject1 a;
a.m_real[2] = 1; // size of m_real == 0 !!!
I think it will better to change design of your class EncapsulatedObjectBase. May be it will better to use:
template<typename T, size_t N> class EncapsulatedObjectBase
{
....
};
class DerivedDataObject1 : public EncapsulatedObjectBase<int,2>
{
....
};
class DerivedDataObject2 : public EncapsulatedObjectBase<double,2>
{
....
};
class DerivedDataObject3 : public EncapsulatedObjectBase<double,2>
, public EncapsulatedObjectBase<int,2>
{
....
};
What I'm trying to do is create a new custom data type that behaves like all other primitive types. Specifically, this data type appears like a Fixed Point fraction.
I've created a class to represent this data type, called "class FixedPoint", and in it there are ways to typecast from "FixedPoint" to "int" or "double" or "unsigned int", etc. That is fine.
Now, what if I want to cast from "int" to "FixedPoint"? Originally my solution was to have a constructor:
FixedPoint(int i) { /* some conversion from 'int' to 'FixedPoint' in here */ }
This works...but you cannot put it into a union like so:
union {
FixedPoint p;
};
This will break, because "FixedPoint" does not have an implicit trivial constructor (we just defined a constructor, "FixedPoint(int i)").
To summarize, the whole issue is "we want to cast from some type T to type FixedPoint without explicitly defining a constructor so we can use our type FixedPoint in a union".
What I think the solution is but cannot find any evidence online:
Define an overloaded global typecast operator to cast from "int" to "FixedPoint".
Is there a way to do this without using class constructors? I'd like to be able to use this class in a union. What I've tried (in global scope):
operator (FixedPoint f, int a) { ... } //compiler complains about this is not a method or non-static.
And a little example to show unions don't like constructors (they like POD)
class bob
{
public:
bob(int a) { m_num = a; }
private:
int m_num;
};
void duck()
{
union
{
bob a;
};
}
This error seen in Visual Studio is:
error C2620: member 'duck::<unnamed-tag>::a' of union 'duck::<unnamed-tag>' has user-defined constructor or non-trivial default constructor
Any ideas?
Thanks
I am having a hard time at seeing what you would try to use this for. It seems smelly to have to constantly ensure that sizeof(FixedPoint) == sizeof(int) and, assuming that, there are other hidden gotchas, like endianness. Maybe I should back up a little bit here, unions only "convert" a value from one type to another in that it takes a chunk of memory and references it as a different type. i.e.
union BadConverter
{
int integer;
double fraction;
};
BadConverter.fraction = 100.0/33.0;
BadConverter.integer = ?;
I am pretty sure integer is not going to be 3, it is going to whatever the memory chunk of the double is that the integer bytes share with it.
Unions don't seem to be a very good fit for this sort of thing. I would think just defining a bunch of assignment operators from all the primitive types. i.e.
class FixedPoint
{
FixedPoint& operator=(int value);
FixedPoint& operator=(double value);
..etc..
//Maybe something like this?
template<typename T>
FixedPoint& operator=(const T& value)
{
value = boost::lexical_cast<int>(value);
return *this;
}
}
Custom conversion operators must be a member of the class that is being converted from. A non-trivial constructor is not required.
EDIT: I reworked the example to utilize a union since this is what you were asking about.
EDIT2: See below if you are trying to go the other way (construction) and don't want constructors.
#include <string>
#include <sstream>
using namespace std;
class FixedPoint
{
public:
operator std::string() const
{
stringstream ss;
ss << x_ << ", " << y_;
return ss.str();
}
int x_, y_;
};
union Items
{
FixedPoint point_;
int val_;
};
int main()
{
Items i;
i.point_.x_ = 42;
i.point_.y_ = 84;
string s = i.point_;
}
If you're trying to go the other way -- eg, from an int to FixedPoint in my example -- then the normal way to do this is indeed to use a conversion constructor. Given that you don't want a non-trivial constructor, you have to resort to a conversion function.
FixedPoint make_fixed_point(int x, int y)
{
FixedPoint ret;
ret.x_ = x;
ret.y_ = y;
return ret;
}
union Items
{
FixedPoint point_;
int val_;
};
int main()
{
Items i;
i.point_ = make_fixed_point(111,222);
}
Can't you just add a default constructor that'll allow it to be part of the union.
For example:
class bob
{
public:
bob(int a=0) { m_num = a; }
private:
int m_num;
};
void duck()
{
union
{
bob a;
};
}
By giving the a=0 default, it should be able to be put in a union. I didn't try it myself, though.