I am trying to pass a custom c++ object reference to a simple chai script so that the chai script can eventually read/access/call public variables & methods.
I'm not certain if this is even possible, nor if once it is passed inside of the chai script function if it will have access to the classes values without having the class previously defined within chai... Any insight would be very helpful, as I can't find a specific section in the documentation relating to this.
Here is a very basic implementation.
ChaiScript.h
#pragma once
#include "ChaiScript\include\chaiscript\chaiscript.hpp"
class ChaiScript
{
public:
explicit ChaiScript(
const std::string& script_name);
~ChaiScript();
chaiscript::ChaiScript chai;
private:
};
ChaiScript.cpp
#include "ChaiScript.h"
ChaiScript::ChaiScript(
const std::string& script_name)
{
chai.add(chaiscript::vector_conversion<std::vector<int>>());
chai.eval_file(script_name);
}
ChaiScript::~ChaiScript()
{
}
SampleClass.h
#pragma once
#include <string>
class SampleClass
{
public:
SampleClass(
const int id,
const int x,
const int y,
const std::string& name);
const int m_id;
int m_x;
int m_y;
std::string m_name;
private:
// Disable copying as we don't want to make a copy each time we pass the class to chai...
SampleClass();
SampleClass(const SampleClass& rhs);
SampleClass& operator=(const SampleClass& rhs);
};
SampleClass.cpp
#include "SampleClass.h"
SampleClass::SampleClass(
const int id,
const int x,
const int y,
const std::string& name) :
m_id(id),
m_x(x),
m_y(y),
m_name(name)
{
}
main.cpp
#include "ChaiScript.h"
#include "SampleClass.h"
int main()
{
SampleClass* sample_class = new SampleClass(0, 1, 2, "Test");
ChaiScript* script = new ChaiScript("Scripts\\SampleScript.chai");
// This line is where I start to need help as it does not compile.
script->chai.eval<std::function<void(&SampleClass)>>("ReceiveSampleClass")(&sample_class);
system("pause");
return 0;
}
SampleScript.chai
def ReceiveSampleClass(SampleClass sample)
{
var result = sample.m_x + sample.m_y;
print("2+2=" + to_string(result));
}
After a bit more searching, I found out how to do this!
I've changed ChaiScript.cpp to the following:
#include "ChaiScript.h"
#include "SampleClass.h"
ChaiScript::ChaiScript(
const std::string& script_name)
{
chai.add(chaiscript::vector_conversion<std::vector<int>>());
chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module());
chaiscript::utility::add_class<SampleClass>(*m,
"SampleClass",
{
chaiscript::constructor<SampleClass(const int id, const int x, const int y, const std::string & name)>()
},
{
{chaiscript::fun(&SampleClass::m_x), "X"}
});
chai.add(m);
chai.eval_file(script_name);
}
ChaiScript::~ChaiScript()
{
}
My SampleScript.chai also changed to:
def ReceiveSampleClass(SampleClass sample)
{
var result = sample.X;
sample.X += 2;
var result2 = sample.X;
print("1) " + to_string(result));
print("2) " + to_string(result2));
}
The process I was missing was adding the class to a module and adding that to chai script.
chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module());
chaiscript::utility::add_class<SampleClass>(*m,
"SampleClass",
{
chaiscript::constructor<SampleClass(const int id, const int x, const int y, const std::string & name)>()
},
{
{chaiscript::fun(&SampleClass::m_x), "X"}
});
chai.add(m);
Related
I'm preparing for an exam of c++. In the last test I failed the cohesion between a class that had the Date date_event as a variable.
How to create different constructors of class P if the class P need an object Data to create an object of the class( the one with no parameters, the one with all the parameters and the copy constructor)?
Also i didn't write this Date actual class. Is it correct to write constructors like that ?
How should giorno(0) , month(0) etc work properly ?
(giorno=day, mese=month, anno= year)
#ifndef DATA_H
#define DATA_H
#include <iostream>
#include <cstring>
using namespace std;
class Data{
friend ostream& operator<<(ostream&, const Data&);
friend istream& operator>>(istream&, Data&);
protected:
int giorno;
int mese;
int anno;
public:
Data(): giorno(0), mese(0), anno(0){}
Data(const int& g, const int& m, const int& a): giorno(g), mese(m), anno(a){}
Data(const Data& D) : giorno(D.giorno), mese(D.mese), anno(D.anno){}
//...
};
#include "Data.h"
class P{
protected:
Data birthday;
public:
P();
P(const int, const int, const int); //i should pass day, month, year right?
P(const P&);
}
Well the question is not clear, but several things can be said.
General
Avoid using namespace std; and use the namespace directly. E.g. friend std::ostream& operator<<(std::ostream&, const Data&);
I suppose this is not the original code, but just in case : don't forget your header guards #ifndef CLASSNAME_H, #define CLASSNAME_H & #endif /* CLASSNAME_H */
Date class
You can implement the constructor that way, but prefer implementing them in the .cpp file.
It is unnecessary to pass the integer parameters as references. Use this for big parameters, from strings to whole objects.
Prefer English for code, even if your colleagues/reviewers/professors are not English. It is always preferred in computer science. This is valid for variable/function names, but also for comments.
P(erson) class
Give your parameters names. Often people that will use your code will only read the headers, so the headers must be as self-explanatory as possible.
For the P contractor, try this :
class Date {
public:
Date(const int pDay, const int pMonth, const int pYear);
Date(const Date &pDate);
/* Getters */
int day(void) const;
int month(void) const;
int year(void) const;
/* Setters */
void setDay(const int pDay);
void setMonth(const int pMonth);
void setYear(const int pYear);
protected:
int mDay;
int mMonth;
int mYear;
};
class Person {
public:
Person(const int pDay, const int pMonth, const int pYear);
Person(const Person &pPerson);
/* Getters */
Date birthday(void) const;
/* Setters */
void setBirthday(const int pDay, const int pMonth, const int pYear);
void setBirthday(const Date &pDate);
protected:
Date mBirthday;
};
Date::Date(const int pDay, const int pMonth, const int pYear):
mDay(pDay),
mMonth(pMonth),
mYear(pYear)
{
/* Empty */
}
Date::Date(const Date &pDate) :
mDay(pDate.day()),
mMonth(pDate.month()),
mYear(pDate.year())
{
/* Empty */
}
int Date::day(void) const {
return mDay;
}
int Date::month(void) const {
return mMonth;
}
int Date::year(void) const {
return mYear;
}
/* Setters */
void Date::setDay(const int pDay) {
mDay = pDay;
}
void Date::setMonth(const int pMonth) {
mMonth = pMonth;
}
void Date::setYear(const int pYear) {
mYear = pYear;
}
Person::Person(const int pDay, const int pMonth, const int pYear):
mBirthday(pDay, pMonth, pYear)
{
/* Empty */
}
Person::Person(const Person &pPerson):
mBirthday(pPerson.birthday().day(), pPerson.birthday().month(), pPerson.birthday().year())
{
/* Empty */
}
Date Person::birthday(void) const {
return mBirthday;
}
void Person::setBirthday(const int pDay, const int pMonth, const int pYear) {
mBirthday.setDay(pDay);
mBirthday.setMonth(pMonth);
mBirthday.setYear(pYear);
}
void Person::setBirthday(const Date &pDate) {
mBirthday.setDay(pDate.day());
mBirthday.setMonth(pDate.month());
mBirthday.setYear(pDate.year());
}
Please note that there are lots of ways to do this in a prettier fashion, and with less data copies.
This is part of a C++ program based on the Alternative Vote electoral method, using VS2015. I have a class for Party
#pragma once
#ifndef _PARTY_H
#define _PARTY_H
#include <string>
class Party {
public:
Party();
~Party();
Party(std::string n, int pos);
void reset();
void upTotal();
int getPosition();
std::string getName();
int getVotes();
private:
std::string name;
int votes;
int position;
};
#endif
and
#include <iostream>
#include "Party.h"
using namespace std;
Party::Party() {}
Party::~Party() {}
Party::Party(string n, int p) {
name = n;
position = p;
}
void Party::reset() {
votes = 0;
}
void Party::upTotal() {
votes += 1;
}
int Party::getPosition() {
return position;
}
string Party::getName() {
return name;
};
int Party::getVotes() {
return votes;
}
I tried to sort on votes received using (calculated from ballot papers elsewhere in the program
void sortParties() {
sort(parties.begin(), parties.end(), [](const auto& a, const auto& b)
{
return a.getVotes() < b.getVotes();
});
}
which returned illegal operand errors. Moving the variables from private to public and writing the following did work
void sortParties() {
sort(parties.begin(), parties.end(), [](const auto& a, const auto& b)
{
return a.votes < b.votes;
});
}
which gets it working, but I want to write it with proper encapsulation using private variables and an accessor for votes. Do I need to overload somehow, or convert type?
You have the following functions defined:
int getPosition();
std::string getName();
int getVotes();
They should probably all be const; ie
int getPosition() const;
std::string getName() const;
int getVotes() const;
This will allow you to call the functions from your const object at
sort(parties.begin(), parties.end(), [](const auto& a, const auto& b)
So I was trying to program a target heart rate calculator in C++ and when I tried to build it, this error was returned. Just to let you know, I am instructed to separate the implementation and interface.
Here's the interface
#include <iostream>
#include <string>
class HeartRates
{
public:
// constructor initialize HeartRates
HeartRates( std::string, std::string, int, int, int );
// Setting each variable
void setFirstName( std::string );
void setLastName( std::string );
void setdobMonth( int );
void setdobDay( int );
void setdobYear( int );
void setCurrentYear( int );
std::string getFirstName() const;
std::string getLastName() const;
int getdobMonth() const;
int getdobDay() const;
int getdobYear() const;
int getCYear() const;
int getAge() const;
int getMaximumHeartRate() const;
int getTargetHeartRate() const;
private:
std::string firstName;
std::string lastName;
int dobMonth;
int dobDay;
int dobYear;
int currentYear;
};
And here's the implementation
#include <iostream>
#include <string>
#include "HeartRates.h"
using namespace std;
// constructor that initializes all the stuff
This is the line that is giving me this error: Out-of-line definition of 'HeartRates' does not match any declaration in 'HeartRates'
HeartRates::HeartRates( string first, string last, int M, int D, int Y, int cY )
{
setFirstName( first );
setLastName( last );
setdobMonth( M );
setdobDay( D );
setdobYear( Y );
setCurrentYear( cY );
}
Continue on with the code
// set functions
void HeartRates::setFirstName( string first )
{
firstName = first; // store the first name in the object
}
void HeartRates::setLastName( string last )
{
lastName = last; // store the last name in the object
}
void HeartRates::setdobMonth( int M )
{
dobMonth = M; // store the month of birth in the object
}
void HeartRates::setdobDay( int D )
{
dobDay = D; // store the day of birth in the object
}
void HeartRates::setdobYear( int Y )
{
dobYear = Y; // store the year of birth in the object
}
void HeartRates::setCurrentYear( int cY )
{
currentYear = cY;
}
// get functions
string HeartRates::getFirstName() const
{
return firstName; // return user's first name
}
string HeartRates::getLastName() const
{
return lastName; // return user's last name
}
int HeartRates::getdobMonth() const
{
return dobMonth;
}
int HeartRates::getdobDay() const
{
return dobDay;
}
int HeartRates::getdobYear() const
{
return dobYear;
}
int HeartRates::getCYear() const
{
return currentYear;
}
// Functions
int HeartRates::getAge() const
{
int age;
age = currentYear-dobYear;
return age;
}
int HeartRates::getMaximumHeartRate() const
{
int maxHeartRate;
maxHeartRate = 220 - getAge();
return maxHeartRate;
}
int HeartRates::getTargetHeartRate() const
{
int targetHeartRate;
targetHeartRate = getMaximumHeartRate() * 0.85;
return targetHeartRate;
}
Sorry for the formatting and copy and pasting everything. Newbie here, I just don't know which part of the code went wrong.
HeartRates( std::string, std::string, int, int, int );
2 strings and 3 int.
HeartRates::HeartRates( string first, string last, int M, int D, int Y, int cY )
2 strings and 4 int.
I had a similar issue today and my fix was slightly different, so I'll throw this here in case it ever helps anyone in the future. I had forward declared a class OUTSIDE of the appropriate namespace in the header, so my error looked something like this:
1. Type of 1st parameter of member declaration does not match definition
'const std::shared_ptr<MyClass> &' (aka 'const shared_ptr<MyClass> &') vs
'const std::shared_ptr<MyClass> &' (aka 'const shared_ptr<myNamespace::MyClass> &'))
The solution for me was to forward declare that class inside the namespace, rather than outside it.
Bad:
class MyClass;
namespace myNamespace {
}
Good:
namespace myNamespace {
class MyClass;
}
I'm trying to access one of my pointers within my class, however I can't seem to even get VS to acknowledge the pointer is there.
private:
ForwardTo* forward;
and here's how I grab it from the class
ForwardTo& Persons::getForwardTo() const
{
return *forward;
}
The ForwardTo type is an inherited class that typically reads:
class ForwardToTwo : public ForwardTo
{
public:
ForwardToTwo(unsigned int strategy);
virtual std::vector<std::string> forwardMessage(Persons& person, Message& message);
unsigned int getStrategy() const { return strategy;};
private:
unsigned int strategy;
};
and finally, here's how I'm trying to access the pointer
listOfPersons.at(i).getForwardTo()->forwardMessage(listOfPersons.at(i), tempMessage);
This style of access worked previously for my OTHER pointer in my class that acts exactly this same as this one.
While typing the line to access the pointer out in VS, intelliSense picks up all the functions up to getForwardTo(), and after that, the dot operator/arrow operator don't bring up any access to functions.
Thanks again for all help.
(edit, I'm aware the function fordwardMessage() function will return a vector, I was just typing in the VS until intelliSense failed to detect the accessible functions)
(edit 2, I've tried both the . operator and the -> operator, yet neither allow intelliSense to detect any functions.)
(edit 3, additional code:
Here is my Persons Class Header:
#ifndef PERSONS_HPP
#define PERSONS_HPP
#include <string>
#include <vector>
#include <list>
#include <map>
#include "Message.hpp"
#include "TypeOne.hpp"
#include "TypeTwo.hpp"
#include "TypeThree.hpp"
#include "TypeFour.hpp"
#include "TypeFive.hpp"
class ForwardTo;
class ForwardToOne;
class ForwardToTwo;
class ForwardToThree;
class Persons
{
public:
Persons();
~Persons();
void setEmailAddress(std::string email);
std::string getEmailAddress() const;
const std::vector<std::string>& getContactList() const;
void addMessageSeen(Message message);
void addMessageContent(MessageContent mc);
void addInboxMessage(Message message);
void addContact(std::string contact);
void viewContact(const std::vector<std::string>& contacts);
void bumpContact();
void setMessageTypeOne();
void setMessageTypeTwo(unsigned int type);
void setMessageTypeThree(unsigned int quality);
void setMessageTypeFour(unsigned int type, unsigned int quality);
void setMessageTypeFive();
void setForwardTypeOne(unsigned int strategy);
void setForwardTypeTwo(unsigned int strategy);
void setForwardTypeThree(unsigned int strategy);
void printPersonsObj();
std::list<Message> getInbox() const;
MessageType& getForwardWhen() const;
ForwardTo& getForwardTo() const;
private:
std::map<MessageContent, unsigned int> messageList;
std::list<Message> inbox;
std::vector<std::string> contactList;
std::string emailAddress;
ForwardTo* forward;
MessageType* forwardWhen;
};
And here is my Persons.cpp file is:
#include "Persons.hpp"
#include "ForwardToOne.hpp"
#include "ForwardToTwo.hpp"
#include "ForwardToThree.hpp"
#include <iostream>
Persons::Persons()
:emailAddress(""), contactList(), inbox(), messageList()
{
}
Persons::~Persons()
{
//delete forwardWhen;
//delete forwardTo;
}
void Persons::addMessageContent(MessageContent mc)
{
//messageSeen.insert(mc);
}
void Persons::setEmailAddress(std::string email)
{
emailAddress = email;
}
std::string Persons::getEmailAddress() const
{
return emailAddress;
}
void Persons::addContact(std::string contact)
{
contactList.push_back(contact);
}
void Persons::addInboxMessage(Message message)
{
inbox.push_back(message);
}
void Persons::viewContact(const std::vector<std::string>& contacts)
{
for(auto i = contacts.begin(); i != contacts.end(); i ++)
{
std::cout << *i << std::endl;;
}
}
void Persons::setMessageTypeOne()
{
MessageType* forwardWhen = new TypeOne();
}
void Persons::setMessageTypeTwo(unsigned int type)
{
MessageType* forwardWhen = new TypeTwo(type);
}
void Persons::setMessageTypeThree(unsigned int quality)
{
MessageType* forwardWhen = new TypeThree(quality);
}
void Persons::setMessageTypeFour(unsigned int type, unsigned int quality)
{
MessageType* forwardWhen = new TypeFour(type, quality);
}
void Persons::setMessageTypeFive()
{
MessageType* forwardWhen = new TypeFive();
}
void Persons::setForwardTypeOne(unsigned int strategy)
{
ForwardTo* forward = new ForwardToOne(strategy);
}
void Persons::setForwardTypeTwo(unsigned int strategy)
{
ForwardTo* forward = new ForwardToTwo(strategy);
}
void Persons::setForwardTypeThree(unsigned int strategy)
{
ForwardTo* forward = new ForwardToThree(strategy);
}
const std::vector<std::string>& Persons::getContactList() const
{
return contactList;
}
void Persons::bumpContact()
{
std::vector<std::string> tempList = getContactList();
std::string tempContact = tempList.at(0);
for(unsigned int i = 0; i <= tempList.size(); i ++)
{
if(i == tempList.size())
tempList.at(--i) = tempContact;
else
tempList.at(--i) = tempList.at(i);
}
}
void Persons::addMessageSeen(Message message)
{
messageList[*message.getMessageContent()] = message.getMessageContent()->getUniqueID();
}
void Persons::printPersonsObj()
{
std::cout << "PERSONS OBJECT!" << std::endl;
std::cout << "E-mail Address: " << emailAddress << std::endl;
std::cout << std::endl;
}
std::list<Message> Persons::getInbox() const
{
return inbox;
}
MessageType& Persons::getForwardWhen() const
{
return *forwardWhen;
}
ForwardTo& Persons::getForwardTo() const
{
return *forward;
}
Incomplete type normally means that at the point at which you are trying to use getForwardTo, you have not fully declared the ForwardTo class. Indeed in your persons.hop there is only a forward declaration.
Make sure you have included the header that fully declares ForwardTo in the file containing the call site.
getForwardTo() returns a T&, just use the . to access forwardMessage()
Consider the following example:
struct MyStruct {
int a;
int b;
};
I can use macros to set a member from an instance of the struct by doing this:
#define setVar(x,y) instance.x = y
then in any function I can say:
setVar(a, 4)
How can I send in a as a string to the macro? Is that also possible?
setVar("a", 4)
EDIT: There are a bunch of predefined structs with members that are all of type double. I only know what struct I am using by an XML config file that is passed in. After parsing, I have a bunch of strings that are a list of all the data members and values that need to be set. I need to use this list to set values for each of the members in the struct.
It is only possible if you define the struct itself using some macro, for example:
#define MY_STRUCT_STRUCTURE FIELD(a) FIELD(b) FIELD(d) FIELD(e) FIELD(f)
struct MyStruct {
# define FIELD(name) int name;
MY_STRUCT_STRUCTURE
# undef FIELD
bool setVar(char* fieldname, int val)
{
# define FIELD(name) if(strcmp(#name,fieldname)==0){name=val; return true;};
MY_STRUCT_STRUCTURE
# undef FIELD
return false; // name not found
}
};
int main()
{
MyStruct s;
s.setVar("a",1);
s.setVar("b",2);
s.setVar("f",100);
}
I have coded some quick and dirty code, but could give you some ideas, hope that helps. The main trick here is too use unions.
struct MyStruct
{
int a;
double b;
MyStruct()
: a(0), b(0) {}
};
MyStruct instance;
union value
{
long value_a;
double value_d;
} myvalue;
void blah_a(value v)
{
instance.a = v.value_a;
}
void blah_b(value v)
{
instance.b = v.value_d;
}
struct
{
(void)(*fn)(value);
const char* key;
}
lookup_table[] =
{
{ &blah_a, "a" },
{ &blah_b, "b" }
};
void setVar(const char* c, value v)
{
for (int i = 0; lookup_table[i].fn; i++)
if (c == lookup_table[i].key)
(*(lookup_table[i].fn))(v);
}
int main(int argc, char* argv[])
{
value v;
v.value_a = 6;
setVar("a", v);
return 0;
}
Might not be what you are looking for but an alternative solution to macros etc.. would just be some encapsulation and OO design. You can change the Field class to a template later and you will be able to represent anything basically.
You can create a class
class Field
{
public:
Field(const std::string& name, const std::string& type);
virtual ~Field(void);
std::string toString() const;
std::string getName() const;
int getValue() const { return value };
private:
std::string name;
std::string type;
int value;
};
And then a structure class
#pragma once
#include <boost/ptr_container/ptr_deque.hpp>
#include <string>
class Field;
class MyStructure
{
public:
typedef boost::ptr_deque<Field> FieldList;
typedef FieldList::iterator FieldListIter;
typedef FieldList::auto_type AutoField;
MyStructure(void);
MyStructure(const std::string& name);
virtual ~MyStructure(void);
void setName(const std::string& name);
std::string getName() const;
void addField( std::auto_ptr<Field> field );
std::string getFieldValue( const std::string& name ) const;
MyStructure::AutoField removeField( const std::string& name );
std::string toString(void) const;
private:
std::string struct_name;
FieldList fields;
};
And then to use it:
auto_ptr<MySructure> struct_a(new MySructure("StructName1",0) );
struct_a->addField( auto_ptr<Field> ( new Field( "Field1", 1 ) ) );
struct_a->addField( auto_ptr<Field> ( new Field( var_str1, 2) ) );
struct_a->addField( auto_ptr<Field> ( new Field( getName(), getVal() ) ) );