ChaiScript/samples/inheritance.cpp
Bernd Amend cff6a0aced change .clang-format and reformat code with clang-format 11
I initially tried to use the existing .clang-format file,
but it does not match the code style (at least with clang-format 11)
and the formatting is not consistent across files.
Therefore, I decided to rewrite the .clang-format with some personal
preferences.

Used command
  find . -iname "*.hpp" -o -iname "*.cpp" | xargs clang-format -i -style=file
2021-05-24 10:44:15 +02:00

120 lines
3.7 KiB
C++

#include <chaiscript/chaiscript.hpp>
class BaseClass {
public:
BaseClass() = default;
BaseClass(const BaseClass &) = default;
virtual ~BaseClass() = default;
virtual std::string doSomething(float, double) const = 0;
void setValue(const std::string &t_val) {
if (validateValue(t_val)) {
m_value = t_val;
}
}
std::string getValue() const { return m_value; }
protected:
virtual bool validateValue(const std::string &t_val) = 0;
private:
std::string m_value;
};
class ChaiScriptDerived : public BaseClass {
public:
ChaiScriptDerived(const std::vector<chaiscript::Boxed_Value> &t_funcs) {
// using the range-checked .at() methods to give us an exception
// instead of a crash if the user passed in too-few params
tie(t_funcs.at(0), m_doSomethingImpl);
tie(t_funcs.at(1), m_validateValueImpl);
}
std::string doSomething(float f, double d) const override {
assert(m_doSomethingImpl);
return m_doSomethingImpl(*this, f, d);
}
protected:
bool validateValue(const std::string &t_val) override {
assert(m_validateValueImpl);
return m_validateValueImpl(*this, t_val);
}
private:
template<typename Param>
void tie(const chaiscript::Boxed_Value &t_func, Param &t_param) {
t_param = chaiscript::boxed_cast<Param>(t_func);
}
std::function<std::string(const ChaiScriptDerived &, float, double)> m_doSomethingImpl;
std::function<bool(ChaiScriptDerived &, const std::string &t_val)> m_validateValueImpl;
};
int main() {
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&BaseClass::doSomething), "doSomething");
chai.add(chaiscript::fun(&BaseClass::setValue), "setValue");
chai.add(chaiscript::fun(&BaseClass::getValue), "getValue");
chai.add(chaiscript::constructor<ChaiScriptDerived(const std::vector<chaiscript::Boxed_Value> &)>(), "ChaiScriptDerived");
chai.add(chaiscript::base_class<BaseClass, ChaiScriptDerived>());
chai.add(chaiscript::user_type<BaseClass>(), "BaseClass");
chai.add(chaiscript::user_type<ChaiScriptDerived>(), "ChaiScriptDerived");
std::string script = R""(
def MakeDerived() {
return ChaiScriptDerived(
// create a dynamically created array and pass it in to the constructor
[
fun(this, f, d) {
// see here that we are calling back into the 'this' pointer
return "${this.getValue()}${f * d}";
},
fun(this, new_val) {
if (new_val.size() < 5) {
true;
} else {
print("String ${new_val} is too long");
false;
}
}
]
);
}
var myderived := MakeDerived(); // avoid a copy by using reference assignment :=
)"";
chai.eval(script);
BaseClass &myderived = chai.eval<ChaiScriptDerived &>("myderived");
// at this point in the code myderived is both a ChaiScript variable and a C++ variable. In both cases
// it is a derivation of BaseClass, and the implementation is provided via ChaiScript functors
// assigned in the MakeDerived() factory function
//
// Notice that our validateValue() function has a requirement that the new string be < 5 characters long
myderived.setValue("1234");
assert(myderived.getValue() == "1234");
// chaiscript defined function will print out an error message and refuse to allow the setting
myderived.setValue("12345");
assert(myderived.getValue() == "1234");
chai.eval(R"(myderived.setValue("new"))"); // set the value via chaiscript
assert(myderived.getValue() == "new");
// call the other derived method via chaiscript and return the value to c++ land:
std::string retval = chai.eval<std::string>("myderived.doSomething(2,4.3)");
assert(retval == "new8.6");
// The whole process is fully orthogonal
}