Passing a Struct as a Parameter to a Function - function

I'm a beginner to C++ programming, and I'm wondering how you would go about passing a struct as an argument to a function using cin.
The idea of the code is to input the name of a struct from the user, and have that name be passed to a function. Here's what I've been playing around with:
class myPrintSpool
{
public:
myPrintSpool();
void addToPrintSpool(struct file1);
private:
int printSpoolSize();
myPrintSpool *printSpoolHead;
};
struct file1
{
string fileName;
int filePriority;
file1* next;
};
int main()
{
myPrintSpool myPrintSpool;
myPrintSpool.addToPrintSpool(file1);
return 0;
}
This is able to build. However, I wanted something more along the lines of:
class myPrintSpool
{
public:
myPrintSpool();
void addToPrintSpool(struct fileName);
private:
int printSpoolSize();
myPrintSpool *printSpoolHead;
};
struct file1
{
string fileName;
int filePriority;
file1* next;
};
int main()
{
string fileName;
cout << "What is the name of the file you would like to add to the linked list?";
cin >> fileName;
myPrintSpool myPrintSpool;
myPrintSpool.addToPrintSpool(fileName);
return 0;
}
Can anyone help how I would go about doing this? Thanks in advance!

This sort of metaprogramming is, in general, extremely advanced in C++. The reason is, unlike interpreted languages, much of what exists in the source file is lost when the file is compiled. In the executable, the string file1 may not show up at all! (it's implementation dependent, I believe).
Instead, I would recommend doing some sort of lookup. For instance, you can compare the string passed in in fileName to each struct's fileName, or, you can just associate any key with your struct. For instance, if you created a std::map<string, baseStruct*> and inherited all of your structs (e.g. file1, file2, ...) from baseStruct, then you can lookup in the map which struct is associated with the passed in string. The inheritance is important, because you will need polymorphism to insert structs of differing types into the map.
There are many other, more advanced topics that we could get into, but this is the general idea. It's most simple to do some sort of lookup rather than try to instantiate a type at runtime from a string. Here is a more rigorous and more maintainable approach to doing basically the same thing.
EDIT: If you mean you have only one type of struct called 'file1' and you want to instantiate it and pass it to addToPrintSpool, that's different than my previous answer (which applies if, for example, you want to have multiple structs called file1 and file2 and want to infer which struct to use. Figuring out types dynamically from a string is hard, but setting the string in an instance of a known type is straightforward.)
To instantiate and use an instance of file1 you can do this:
//In myPrintSpool, use this method signature.
//You are passing in an object of type file1 named aFile;
//note that this object is _copied_ from someFile in your
//main function to a variable called aFile here.
void addToPrintSpool(file1 aFile);
...
int main()
{
string fileName;
cout << "What is the name of the file you would like to add to the linked list?";
cin >> fileName;
//Instantiate a file1 object named someFile, which has all default fields.
file1 someFile;
//Set the filename of aFile to be the name you read into the (local) fileName var.
someFile.fileName = fileName;
myPrintSpool myPrintSpool;
//Pass someFile by value into addToPrintSpool
myPrintSpool.addToPrintSpool(someFile);
return 0;
}

Related

Returning by reference from struct method in D

I'm starting my journey in D from C++. In C++ passing by reference or value is quite explicit, but in D it seems to vary between structs and classes.
My question is how can I force a return by reference?
I have a simple XmlNode class for building Xml trees (which is a lift from my C++ code):
import std.stdio;
struct XmlNode
{
string _name;
string _data;
XmlNode[] _children;
this(string name, string data="")
{
_name = name;
_data = data;
}
//Trying to return a reference to the added Node
ref XmlNode addChild(string name,string data = "")
{
_children ~= XmlNode(name,data);
return _children[$-1];
}
string toString(bool bPlain = true, string indent = "")
{
//Omitted for brevity
}
}
And here is the testing code:
int main()
{
auto root = XmlNode("root");
//Chained call
root.addChild("Level 1").addChild("Level 2","42");
//Call in two parts
auto n = root.addChild("Level 1");
n.addChild("Level 2","101"); //n seems to be a copy not a reference
//Chained call
root.addChild("Level 1").addChild("Level 2","999");
writeln(root.toString(false));
return 0;
}
which gives the following output:
root
Level 1
Level 2
42
Level 1
Level 1
Level 2
999
As you can see the 'chained' use of addChild() performs as hoped. But if I try to break it up into two separate calls, only the first has an effect, and the second seems to operate on a copy of the first, not a reference. I optimistically added a ref qualifier to the addChild() signature, but that doesn't seem to help.
As ever, I'd be grateful for any advice (using DMD / Visual D / Visual Studio / Windows 10).
auto n = root.addChild("Level 1");
Here, though addChild returns a reference, it is assigned to a variable, and thus dereferenced and copied. Instead, you probably want:
auto n = &root.addChild("Level 1");
Note that D does not have reference variables, like in C++. Variables can be only pointers (though it's possible to write a wrapper template with reference-like semantics).
Also note that in the current design of XmlNode, the returned reference will only be valid until the next time _children is modified (as that may cause a reallocation and thus move the contents to another address, making any extant references outdated). It is a common footgun, which could be avoided by storing references of XmlNode (or making it a reference type i.e. a class), at the cost of extra dereferences and allocations.

Convert an instance of QObject to JSON

I have some code that I am using to convert arbitrary QObject subclasses to JSON. I able to convert them if they are pointers to a subclass, but am curious whether it is possible to convert instances (provided the subclass implements a copy constructor). Is there some crazy way to use something like templates or the type information provided by QMetaType to copy an instance of a QObject subclass without knowing what it is? The ToJson code is in a class that has no knowledge of the subclass.
I think it might be possible with QMetaType::create or something similar but I haven't been able to figure out how to actually copy the properties of the subclass instance.
Here's my code for converting:
QJsonValue ToJson(QVariant value){
switch(value.type()){
case QVariant::Int:
case QVariant::Double:
return value.toDouble();
////Other cases, etc...
case QVariant::UserType:
QObject* obj_ptr = qvariant_cast<QObject*>(value);
if(obj_ptr) // value was originally a pointer to a QObject, works correctly
return ToJson(obj_ptr);
else { // value was orginally an instance of a QObject subclass
std::string t = value.typeName(); //returns "MyQObject"
int id = QMetaType::type(t.c_str()); //returns the id of the derived class
void* v = QMetaType::create(id, &value); //passing &value does nothing
obj_ptr = static_cast<QObject*>(v);
return ToJson(obj_ptr); //works, but resulting fields are all default
}
}
}
QJsonObject ToJson(QObject* o){
QJsonObject obj;
auto mo = o->metaObject();
for (int i = mo->propertyOffset(); i < mo->propertyCount(); ++i){
QVariant value = o->property(mo->property(i).name());
obj[mo->property(i).name()] = ToJson(value);
}
return obj;
}
Sample code use case:
qRegisterMetaType<MyQObject>();
MyQObject obj;
obj.db = 11.1;
QVariant test1 = QVariant::fromValue(obj);
QVariant test2 = QVariant::fromValue(&obj);
QJsonValue v1 = ToJson(test1); // default constructed values
QJsonValue v2 = ToJson(test2); // db = 11.1
Sample QObject subclass:
class MyQObject : public QObject {
Q_OBJECT
Q_PROPERTY(double DB MEMBER db)
Q_PROPERTY(int I MEMBER i)
public:
MyQObject();
MyQObject(const MyQObject& other) : QObject() {
i = other.i;
db = other.db;
}
int i = 50;
double db = 1.5;
};
Q_DECLARE_METATYPE(MyQObject)
Is there any way to handle the case illustrated by test1 above?
Long-story-short: nope. There is no way to store QObjects by value in containers or QVariant.
Qt forbids the copy of QObjects and all inheriting classes. The mandatory the Q_OBJECT macro will disable any copy constructor also in newly defined classes.
The copy constructor that you are defining in the MyObject class is missing the base class constructor call. If QObject had a copy constructor it would be something like this:
MyQObject(const MyQObject& other) :
QObject(other) // this will NEVER compile
{
i = other.i;
db = other.db;
}
Probably, the compiler is giving you a warning, but allows you to have such a constructor, even if it will result in undefined behavior or slicing an instance of MyObject every time it is passed by value.
Furthermore, the Qt docs states the following:
The values stored in the various containers can be of any assignable
data type. To qualify, a type must provide a default constructor, a
copy constructor, and an assignment operator. This covers most data
types you are likely to want to store in a container, including basic
types such as int and double, pointer types, and Qt data types such as
QString, QDate, and QTime, but it doesn't cover QObject or any QObject
subclass (QWidget, QDialog, QTimer, etc.).
So you can't store QObject and derived classes inside a Qt container unless you store them as pointers, as copy of QObjects is disabled by design.
Furthermore, if you want to exploit polymorphic behavior you must use pointers, even if there is no explicit need to cast to derived classes in your code, as far as I can see. If you really need to resort to casting in some place, you could consider making your ToJson a template function.
There is a solution, but use caution as it is only reasonable/applicable in the following scenario:
Classes in question are primarily data storage classes
The classes in question would be entirely copy-able if they didn't inherit from QObject
Most importantly, the ONLY reason you have the class inherit from QObject is so that it can have meta properties.
If your code uses the class as a QObject for any reason other than to get meta information, you are almost certainly using it incorrectly if you are trying to store it by value (as explained by G. Giordano in their answer).
Misuse considerations aside, in order to JSON-ify a QVariant that stores a QObject subclass by value, you can use the QMetaType::create method and pass it the user type id and yourQVariant.constData().
Example:
MyQObject obj;
obj.db = 11.1;
QVariant value = QVariant::fromValue(obj);
std::string t = value.typeName();
int id = QMetaType::type(t.c_str());
void* v = QMetaType::create(id, value.constData());
obj_ptr = static_cast<QObject*>(v);
QJsonValue json = ToJson(obj_ptr); //json contains db = 11.1

Using a Struct Inside of a Function

I have a struct, file, and a class with functions in it. I'm trying to create a linked list of structs in my function, but I can't quite understand how to go about doing it! Here's my work thus far for that portion of my code:
#include <iostream>
using namespace std;
class myPrintSpool
{
public:
void send(string);
private:
int printSpoolSize;
myPrintSpool *printSpoolHead;
myPrintSpool* next;
};
struct file
{
string fileName;
int filePriority;
file* next;
};
void myPrintSpool::send(string name)
{
//Adds to linked list
file file;
myPrintSpool* file = new myPrintSpool;
if(printSpoolHead == NULL)
{
printSpoolHead = file;
}
else
{
file->next = printSpoolHead;
printSpoolHead = file;
}
printSpoolSize++;
}
I send a string inside the function so that when the user inputs a file name to send, it changes the name of the struct to that fileName in struct file changes to that input name. However, I'm not sure what to do since I cannot get the above portion to work properly first.
Thank you in advance, and thank you for taking the time to help me out!
It's been a while since I've done any C++, so this is all from recollection. In the code you supplied, you aren't instantiating a class. You are allocating memory for one.
If you want to assign a new class to that memory:
myPrintSpool printSpool = new myPrintSpool();
myPrintSpool *file = &printSpool;
I'm somewhat confused as to what you are actually doing. It seems the printSpoolHead will always be equal to the current myPrintSpool object, and if it's anything other than the first instantiation, it points back to itself.
As you didn't say anything specific as to the location of your error(s), do a simple output to verify the function is doing what you think it should (or is) doing.
Edit: Actually, I recall being thrown off by C++ instantiation, so it may be:
myPrintSpool printSpool;

How to automagically generate JSON serialisers and deserialisers for structs/classes at runtime in D?

I'm still new to D, but an obvious missing feature (for web developers) in
http://www.digitalmars.com/d/2.0/phobos/std_json.html
is a mixin which creates JSON serialisers and deserialisers for arbitrary (nests) of structs and classes.
i.e.
struct Dog {
string name;
int age;
}
struct Person {
mixin JSON;
string name;
int age;
string[] favouriteFoods;
Dog dog;
bool retired () { return age > 65 };
}
then be able to
auto p = Person("\"name\":\"Fred\",\"age\":45,\"favouriteFoods\":[\"cheese\",\"bananas\"],\"dog\":{\"name\":\"Rover\",\"age\":7}");
p.dog.name -> "rover"
p.favouriteFoods[1] -> "bananas"
p.retired() -> false
and
p.toJSON(); -> "\"name\":\"Fred\",\"age\":45,\"favouriteFoods\":[\"cheese\",\"bananas\"],\"dog\":{\"name\":\"Rover\",\"age\":7}"
Would this be possible using the various meta programming features of D?
Thanks,
Chris.
Yes this is possible (I have a library which does exactly this in production right now), and D makes it pretty easy to implement using compile-time reflection. You'll want to read up at these links:
Traits (compile feature)
std.traits (library)
Template Mixins
String Mixins

SWIG and triggering a Python callback from C code

Apologies for not being familiar with formatting on here...I've made
some progress thanks to helpful replies and edited and removed my original
question to be replaced by the current one.
My problem lies with converting a C struct or struct pointer to PyObject. There
is no alternative to this because I am wrapping an existing C library whose
callback requires a C struct pointer.
Following works but with limitations:
%module cain1
%{
typedef struct {
double price;
int volume;
} book_entry_t;
typedef struct {
char symbol[10];
book_entry_t *book;
} trade_t;
typedef void (*CALLBACK)(trade_t trade);
CALLBACK my_callback = 0;
static PyObject *my_pycallback = NULL;
static void bigSnake(trade_t trade)
{
PyObject *result;
PyObject *d1;
result = PyEval_CallObject(my_pycallback,
Py_BuildValue("(y#)",
(char*)&trade,
sizeof(trade_t)
)
);
Py_XDECREF(result);
return /*void*/;
}
void test_cb (PyObject *callMe1) {
trade_t d1;
book_entry_t b1;
b1.price = 123.45;
b1.volume = 99;
Py_XINCREF(callMe1); /* Add a reference to new callback */
my_pycallback = callMe1; /* Remember new callback */
strcpy (d1.symbol,"Gupta Ltd");
d1.book = &b1;
bigSnake(d1);
}
%}
// Expose in python module..
typedef struct {
double price;
int volume;
} book_entry_t;
typedef struct {
char symbol[10];
book_entry_t *book;
} trade_t;
void test_cb(PyObject *callMe1);
and then triggering the callback from Python:
import cain1
import struct
def dave(d1):
N1,N2 = struct.unpack('10sP', d1)
print ('\n %s: %x' % (N1.decode() ,N2))
price,volume = struct.unpack('di',N2)
print (price,volume)
def main():
cain1.test_cb(dave)
main()
but I am unable to recover the book_entry_t strcut contents pointed to by trade_t....
I just feel this is all too convoluted since I have the pointer to structs and there
must be a straightforward way for Python to use that without any fuss.
Py_BuildValue("(N)",details) expects a PyObject* (your "N" says so), and you pass it something very different. Try Py_BuildValue("(i)", details.index) instead, and change it to accomodate any changes in details_t.
You're attempting to build a PyObject from a details_t struct. This isn't valid. Either pass the callback an integer (seems easier since details_t only has the one field) OR create a proper PyObject type. You can't blindly cast one type to another and expect it to work (a PyObject is more than just a pointer).