How to simplify structs using a template? - c++

I have a piece of code, copied below, with really similar structs in which just one member changes type. I am looking to simplify it. I was considering using a template, but I am not too sure how would it be the syntax between a struct and a template. Any pointer would be greatly appreciated.
typedef struct pos_parameter{
float magnitud;
bool new_value;
} pos_parameter;
typedef struct feed_parameter{
double magnitud;
bool new_value;
} feed_parameter;
typedef struct speed_parameter{
long magnitud;
bool new_value;
} speed_parameter;
typedef struct g_code_parameter{
int magnitud;
bool new_value;
} g_code_parameter;
typedef struct position{
pos_parameter X;
pos_parameter Y;
pos_parameter Z;
pos_parameter A;
} position;
typedef struct move{
position pos;
feed_parameter feedrate;
speed_parameter speed;
g_code_parameter g_code;
} move;

template <typename T>
struct parameter{
T magnitud;
bool new_value;
};
Example use:
parameter<float> pos_parameter;
parameter<double> feed_parameter;
parameter<long> speed_parameter;
parameter<int> code_parameter;
Hope that helps.

One quick observation before we get in to genericizing the magnitud member variable. Your use of the typedef struct {/*...*/} name; syntax is not needed, and very non-idiomatic in C++. In C this may be needed, but C++ is not C. In C++, you can simply:
struct Gizmo
{
/* ... */
};
Now, in order to genericize the type of the magnitud member variable, you can create a class template like this:
template<class MAG> struct basic_parameter
{
MAG magnitud;
bool new_value;
};
You would declare an instance of such a thing like this:
basic_parameter<int> myparam;
You can also use a typedef to create a kind of "alias" for certian specializations of basic_parameter, like this:
typedef basic_param<int> int_param; // Now int_param is shorthand for basic_param<int>
/* ... */
int_param myparam; // myparam is of type basic_param<int>
You can use this technique to create typedefs for all the different kinds of parameters you were using in the position and move structures, and make it so that you don't have to change the code for those types.
Here is a complete solution:
template<class MAG> struct basic_parameter
{
MAG magnitud;
bool new_value;
};
typedef basic_parameter<float> pos_parameter;
typedef basic_parameter<double> feed_parameter;
typedef basic_parameter<long> speed_parameter;
typedef basic_parameter<int> g_code_parameter;
struct position {
pos_parameter X;
pos_parameter Y;
pos_parameter Z;
pos_parameter A;
};
struct move
{
position pos;
feed_parameter feedrate;
speed_parameter speed;
g_code_parameter g_code;
};
int main()
{
}

I guess the first four could be :
template<typename T>
struct pos_parameter{
T magnitud;
bool new_value;
};

template<typename T>
struct generic_parameter
{
T magnitud;
bool new_value;
};
There you go

Related

typedef usage in struct definition

I have problem with this code,this is a header file(stack.h) from a maze program. i was studying Stack structure, and in my documents, i couldn't understand these type of structures, can anyone explain to me why we are using typedef and how the 12th and 21st line works??
#ifndef STACK_H
#define STACK_H
#define STACKSIZE 50
typedef struct d {
int x;
int y;
int right; int left;
int down;
int up;
int camefrom;
} StackDataType, position; /// LINE 12
struct STACK{
StackDataType element[STACKSIZE]; int top;
void create();
void close();
bool push(StackDataType); StackDataType pop();
bool isempty();
};
typedef struct STACK Stack; /// LINE 21
#endif
I think you do not need to typedef a struct again in C++, it again defines a struct, which is unnecessary. You can just define:
struct d{
};
In my (considerable) experience, this almost always denotes a C programmer who has fumbled their way into C++. If these are notes from your classes, it doesn't bode well.
In the earliest "C", if you declared a struct
struct StructName {
int a;
int b;
};
This didn't declare a type name, it only declared a struct name, so to make an instance of StructName you would have to write:
struct StructName myStruct;
If you wanted to be able to omit the "StructName" part you would need to use a typedef:
struct StructName { int a, b; };
typedef struct StructName StructName;
Or you could combine these into one, somewhat confusing, statement:
typedef struct StructName { int a, b; } StructName;
I say confusing because if the struct definition is many lines long, it could be confused for a second C syntax which lets you declare an instance of a Struct after defining the type:
struct StructName { int a, b; } StructName;
// aka
struct StructName { int a, b; };
struct StructName StructName; // local variable, StructName of type struct StructName
// declare a VARIABLE called StructName which is of type anonymous-struct.
struct { int a, b; } StructName;
One problem with this is that you can't use the typedef'd name in the structure declaration:
// Won't compile because 'List' isn't declared until the end.
typedef struct list_structure { List* next; int a; } List;
// Won't compile because you have to remember to say 'struct List'
typedef struct List { List* next; int a; } List;
// Compiles
typedef struct list_structure { struct list_structure* next; int a; } List;
This confused a lot of C programmers. Enough so that many C programmers will tell you that the definition of a struct is
typedef struct tag_name { /* struct details */ } structname;
//e.g.
typedef struct tagStructName { int a, b; } StructName;
C++ inherited all of this, but also went ahead and made the typedef implied for you:
// doesn't compile as C, will compile as C++
struct List {
List* next;
int a;
};
To see it not compiling as C: http://ideone.com/3r9TRy
In C++, declaring something as a class is exactly the same as declaring it a struct, with one change:
class List {
List* next;
public:
int a;
};
Is EXACTLY as though you had written:
struct List {
private:
List* next;
public:
int a;
};
There's no other difference between a struct and a class in C++.
I can see two problems: The first is the mysterious symbol  in the definition of the d structure. The second is that you use typedef for that structure too, but have something after the typename StackDataType. The second error you get is probably just because of the first one, it's very common in C and C++ to get errors in unrelated lines because of previous errors.
Besides, in C++ you don't really need typedef for structures, as they are the same as classes so doing e.g. struct StackDataType {...}; will allow you to use StackDataType as a type.
What's going on is that essentially the typedef is being used to create a shorthand way to refer to the given structure.
So in this example, both StackDataType and position are shorthand references to what is formally declared as struct d, and Stack is a shorthand reference to what is formally declared as struct STACK.
Generally speaking, this allows for cleaner code referencing these structures. E.g., instead of having to write:
struct STACK var;
to declare an instance of this structure, you can just use:
Stack var;
You can declare a typedef either at the same point at which you declare the type (as in the first example), or you can declare it later (as in the second).

Idiom for strict typedef in C++

Is there an idiom for a strict typedef in C++, possibly using templates?
Something like:
template <class base_type, int N> struct new_type{
base_type p;
explicit new_type(base_type i = base_type()) : p(i) {}
};
typedef new_type<int, __LINE__> x_coordinate;
typedef new_type<int, __LINE__> y_coordinate;
So I can make something like this a compile time error:
x_coordinate x(5);
y_coordinate y(6);
x = y; // whoops
The __LINE__ in there looks like it might be trouble, but I'd prefer not to have to manually create a set of constants merely to keep each type unique.
I'm using something similar in my project. Only I use type tagging instead of int. Works well in my particular application.
template <class base_type, class tag> class new_type{
public:
explicit new_type(base_type i = base_type()) : p(i) {}
//
// All sorts of constructors and overloaded operators
// to make it behave like built-in type
//
private:
base_type p;
};
typedef new_type<int, class TAG_x_coordinate> x_coordinate;
typedef new_type<int, class TAG_y_coordinate> y_coordinate;
Note that TAG_* classes don't need to be defined anywhere, they are just tags
x_coordinate x (1);
y_coordinate y (2);
x = y; // error
No. There are proposals for it to go into the next standard (C++14, or perhaps C++17), but not in C++11.
With C++11:
#include <stdio.h>
struct dummy {};
struct NotMineType
{
NotMineType(dummy) {}
};
template <int N>
struct type_scope
{
struct MyOwnType
{
};
struct ConvertedToMineType : NotMineType
{
template <typename ...Args>
ConvertedToMineType(Args... args) : NotMineType(args...) {};
};
enum myint : int {};
};
typedef type_scope<0>::MyOwnType x1;
typedef type_scope<1>::MyOwnType x2;
typedef type_scope<0>::ConvertedToMineType y1;
typedef type_scope<1>::ConvertedToMineType y2;
typedef type_scope<0>::myint i1;
typedef type_scope<1>::myint i2;
void foo(x1) { printf("x1\n"); }
void foo(x2) { printf("x2\n"); }
void foo(y1) { printf("y1\n"); }
void foo(y2) { printf("y2\n"); }
void foo(i1) { printf("i1\n"); }
void foo(i2) { printf("i2\n"); }
int main()
{
foo(x1());
foo(x2());
foo(y1(dummy()));
foo(y2(dummy()));
foo(i1());
foo(i2());
}
Output:
x1
x2
y1
y2
i1
i2
Compilers:
Visual Studio 2015, GCC 4.8.x

Simple example with templates

This is a simple question, and I am sure that it has been answered before but I cannot seem to find a good answer.
I have a class, Point:
template<class T>
Point{
\\code
}
...and now I want a vector of Points, some of which have T as an integer which have T as a double. I want to write something like
template<class T>
std::vector<Point<T> > points;
But, alas, this doesn't compile with the error "expected primary-expression before 'template'". I haven't been able to fidget with this code to make it work. Also relevant is that points is in the main class, so I can't stick the template declaration outside the function.
If someone could direct me to a solution, I would be much obliged.
Thanks.
If your goal is to have a vector that holds both Point<int> and Point<double> you can use Boost Variant.
typedef boost::variant<Point<int>, Point<double> > VariantPoint;
Then:
std::vector<VariantPoint> my_vector;
my_vector.push_back(Point<int>(1, 0));
my_vector.push_back(Point<double>(1.5f, 2.0f));
Will work. Note that to inspect the elements afterwards, you probably will have to use the visitor pattern as documented here.
If your goal is to have distinct vector types that can only hold one type of Point, then you may use:
template<typename T> using PointVector = std::vector<Point<T>>; // C++11
// Now you can write:
PointVector<int> my_vector;
// Which is equivalent to:
std::vector<Point<int>> my_vector;
Or, if C++11 is not an option:
template<typename T> struct PointVector
{
typedef std::vector<Point<T> > Type;
}
Then:
PointVector<int>::Type my_vector;
To get a single kind of vector, I would use inheritance:
template <typename T>
struct PointVector : public std::vector< Point<T> >
{
};
Note, the inheritance is just a mechanism to achieve the equivalent of a template typedef. This means, PointVector should not contain any data members or virtual functions. However, #ereOn's suggestion is preferred, and is discussed in the answer to this question.
The old fashioned way to achieve a variant would be to use a union.
class IntOrDouble {
union {
int i;
double d;
};
bool is_int;
bool is_double;
public:
IntOrDouble () : is_int(false), is_double(false) {}
IntOrDouble (int x) : is_int(true), is_double(false) { i = x; }
IntOrDouble (double x) : is_int(false), is_double(true) { d = x; }
int operator = (int x) {
is_int = true;
is_double = false;
return i = x;
};
double operator = (double x) {
is_int = false;
is_double = true;
return d = x;
};
operator int () const {
if (is_int) return i;
if (is_double) return d;
return 0;
}
operator double () const {
if (is_double) return d;
if (is_int) return i;
return 0;
}
};
typedef std::vector< Point<IntOrDouble> > PointVector;
But it all seems a little over the top for this use case. I'd just use vectors of double all around, unless memory was really tight.

Named Structures in C++ Unions

In C++, I'm trying to create a specialized point class as a union, like so:
union point
{
struct { float x, y, z; };
float val[3];
float operator[](unsigned i) { return val[i]; }
};
So that I can access the point as an array or as multiple points, for readability.
However, let's say that I want to generalise this a bit:
template<unsigned n>
union point
{
struct { float ???; };
float val[n];
float operator[](unsigned i) { return val[i]; }
};
What can I put for ???? I could have x, x, y, x, y, z, or x, y, z, w depending on what n is. Solution? Forward declarations!
template<unsigned n>
union point
{
struct coords;
float val[n];
float operator[](unsigned i) { return val[i]; }
};
template<>
struct point::coords<3>
{
float x, y, z;
};
// ...
But this doesn't appear to work. Under the GCC 4.6, it compiles, however, whenever that I try to use the members, like so:
point<3> val;
val.x;
I get the error:
error: ‘union point<3>’ has no member named ‘x’
Even if I change val.x to val.coords::x, I still get the error:
error: ‘union point<3>::coords’ is not a base of ‘union point<3>’
Adding using coords; in the union definition didn't help, either.
Is there any way to accomplish this under the GCC 4.6? Is there a different method of doing this? Is it even possible?
I would suggest using variadic macro to define your union<N> templates.
template<unsigned int N>
union point; // declared and undefined
#define DECLARE_POINT(NUM, ...) \
template<> \
union point<NUM> \
{ \
struct { float __VA_ARGS__; }; \
float val[NUM]; \
}
#undef DECLARE_POINT
Having done this, you can simply declare/define your various combinations for coordinates (before #undef in this case):
DECLARE_POINT(1, x);
DECLARE_POINT(2, x, y);
DECLARE_POINT(3, x, y, z);
that is equivalent to,
template<> union point<1> { struct { float x; }; float val[1]; };
template<> union point<2> { struct { float x, y; }; float val[2]; };
template<> union point<3> { struct { float x, y, z; }; float val[3]; };
It can be used in the same way you asked:
point<3> p;
p.z = 0;
Also, you can put a cross check using some template trickery (static_assert) to check the number arguments(e.g. 1,2,3,...) match the total argument passed (e.g. x,y,z,...).
This line inside your union:
struct coords;
forward-declares the type coords, but there's no struct coords field in your templated union.
Besides, only members of anonymous structures can be accessed as top-level fields of an union. For instance:
union foo {
struct { // anonymous struct
short i;
short j;
};
int k;
};
foo f;
// it's possible to access the fields of the anonymous struct as if they were
// direct members of the union
f.i = 4;
f.j = 8;
std::cout << f.k;
I'm not sure you'll be able to do that if you only specialize the inner struct type.
However, this works:
template<unsigned n>
union point;
template<>
union point<2> {
struct { float x, y; };
float val[2];
};
template<>
union point<3> {
struct { float x, y, z; };
float val[3];
};
There is a number of downsides though; the main one being that you'll have to redefine operator[] for each version of point.
I know how to use templates but I'm no template god, so it's not out of question that a clever trick exists.

C++ typedef and struct question

typedef struct
{
int y;
int weight;
struct edgenode * next;
}edgenode;
This code is giving error : 'edgenode' : redefinition; different basic types
It works fine in C code.
Why?
Because your struct doesn't have a name! The question suggests a C heritage - the code is written the way I'd write it.
The pure C++ solution is:
struct edgenode
{
int y;
int weight;
edgenode *next;
};
This will not work in C. In C, and consistent with the question, you would write:
typedef struct edgenode
{
int y;
int weight;
struct edgenode * next;
} edgenode;
Now your struct has a name - struct edgenode. There is also a typedef for it, of course - edgenode, but the compiler doesn't know about that name until it reaches the final semi-colon (approximately). You could also write:
typedef struct edgenode edgenode;
struct edgenode
{
int y;
int weight;
edgenode *next;
};
try:
struct edgenode
{
int y;
int weight;
edgenode* next;
};
In C++ it is no longer required to use the typedef on struct nodes.
Also the way you were using it (for C) was wrong. if you typedef it then there is no need to use struct anymore.
In C you had todo:
// In C:
struct X {};
struct X a;
// C with typedef (Notice here that the struct is anonymous)
// Thus it is only accessible via the typedef (but you could give it a name)
typedef struct {} X;
X a;
// In C++ the use of struct is no longer required when declaring the variable.
struct Y {};
Y a;
No name specified for your struct before you typedef
typedef struct edgenode
{
int y;
int weight;
edgenode* next;
}en;
The difference between C and C++ is, that they treat struct-names and typedef names differently. In C you can not refer to a struct without using the "struct" keyword unless you create typedef name which resolves to the struct name. Therefore this is valid in C, but not in C++:
struct A {};
typedef int A;
int main()
{
A a;
struct A a;
}
structs and typedefs live in a different namespace if you want to. However in C++, both struct and typedef names go into the same namespace. There can be only one A and therefore this example does not compile. So how does this apply to your example? Let's read it the C way:
typedef struct // Here's an unnamed struct
{
int y;
int weight;
struct edgenode * next; // Oh, yes points to some struct called "edgenode" that we don't know of
}edgenode; // and we want to refer to this structs as "edgenode"
This declaration actually created two things called edgenode: A typedef (for the unnamed struct) and an incomplete type "struct edgenode" that is not defined anywhere. You will notice that edgenode x; x.next->y will not compile.
Here's how C++ reads it:
typedef struct // Here's an unnamed struct
{
int y;
int weight;
struct edgenode * next; // Oh, yes points to some struct called "edgenode" that we don't know of
}edgenode; // and we want to refer to this as "edgenode"..HEY WAITASECOND! There's already SOME OTHER THING named edgenode. We know this, because "next" mentioned it!!