I have a .proto file which consists of following messages:
message A {
message B {
optional string Header = 1;
optional string Value = 2;
}
repeated B Inputs = 1;
}
message BuildConfig {
optional A Options = 1;
}
In my pb.h file there are following functions:
class BuildConfig:
inline const ::google::protobuf::RepeatedPtrField< ::NBuildModels::NProto::A >&
GetOptions() const { return options(); }
class A:
inline const ::google::protobuf::RepeatedPtrField< ::NBuildModels::NProto::A_B >&
GetInputs() const { return inputs(); }
I am trying to access Head and Value like this:
void foo(const NBuildModels::NProto::BuildConfig& config) {
auto a = config.GetOptions();
auto b = a.GetInputs();
}
However, it does not work with the following error : No member named 'GetInputs' in 'google::protobuf::RepeatedPtrFieldNBuildModels::NProto::A'
What protobuf syntax do you use? What protogen do you use? Neither of known me protogen generates the C++ methods GetOptions and GetInputs. This works for me after Google protogen with syntax = "proto3";:
auto& a = config.options();
auto& b = a.inputs();
I'm trying to manually bind a vector of pointers from C++ to Lua.
I'm limited to a compiler which has partial C++11 support, so can't use one of the existing binding libraries since they all seem to use C++17 now.
For example, I have a class which contains a list of pointers to a child class. The vector of children is read only from the Lua point of view - I don't need add, remove etc. Just read.
class Child
{
public:
std::string name;
};
class Parent
{
public:
std::vector <Child *>children;
};
...
Parent parent;
Child * m = new Child;
m->name = "Mary";
parent.children.push_back(m);
Child * b = new Child;
b->name = "Bob";
parent.children.push_back(b);
...
Child binding.
static int Child_name(lua_State * lua) {
// this should get a point to a Child object and return the name
lua_pushstring(lua, "child name");
return 1;
}
static const struct luaL_Reg Child_FunctionList[] = {
{ "name", Child_name },
{ NULL, NULL }
};
static int Child_tostring(lua_State * lua) {
lua_pushstring(lua, "Child");
return 1;
}
static const struct luaL_Reg Child_MetaList[] = {
{ "__tostring", Child_tostring },
{ NULL, NULL }
};
void Child_Register(lua_State * lua)
{
luaL_newlib(lua, Child_FunctionList);
if(luaL_newmetatable(lua, "ChildMetaTable"))
luaL_setfuncs(lua, Child_MetaList, 0);
lua_setmetatable(lua, -2);
lua_pop(lua, 1);
}
Parent binding.
static int Parent_count(lua_State * lua) {
// used by both the Parent function and metatable __len
lua_pushinteger(lua, parent.children.size());
return 1;
}
static int Parent_children(lua_State * lua)
{
// stack -1=number(1)
int idx = lua_tonumber(lua, -1);
Child ** c = static_cast<Child **>(lua_newuserdata(lua, sizeof(Parent *)));
*c = parent.children[idx];
luaL_getmetatable(lua, "ChildMetaTable"); // [-0, +1, m]
lua_setmetatable(lua, -2);
// return new userdata - does not work
return 1;
}
static const struct luaL_Reg Parent_FunctionList[] = {
{ "count", Parent_count },
{ "children", Parent_children },
{ NULL, NULL }
};
static int Parent_tostring(lua_State * lua) {
lua_pushstring(lua, "Parent");
return 1;
}
static int Parent_index(lua_State * lua) {
// stack -1=number(1) -2=table
int idx = lua_tonumber(lua, -1);
Child * c = parent.children[idx];
// what to return here?
return 0;
}
static const struct luaL_Reg Parent_MetaList[] = {
{ "__tostring", Parent_tostring },
{ "__len", Parent_count },
{ "__index", Parent_index },
{ NULL, NULL }
};
void Parent_Register(lua_State * lua) {
luaL_newlib(lua, Parent_FunctionList);
if(luaL_newmetatable(lua, "ParentMetaTable"))
luaL_setfuncs(lua, Parent_MetaList, 0);
lua_setmetatable(lua, -2);
lua_setglobal(lua, "Parent");
}
The Parent binding results in a global table, which is intentional. Testing the Parent table:
>print(Parent)
Parent
>print(#Parent)
2
>print(Parent.count())
2
But trying to access the children doesn't work as well
>c = Parent[1]
>print(c)
Child
>print(type(c))
userdata
>print(c.name())
[string "main"]:8: attempt to index a ChildMetaTable value (global 'c')
I get lost in Parent_index, where I need a pointer to the C Parent object rather than the Lua table. I understand the method is to use userdata or lightuserdata but can't see how to bind the class to Lua in order to do this. Same for the Child binding, which results in a ChildMetatable but no Lua table.
Edit: I've added in a children function under Parent, but still not working. Also changed some of the indexes for lua_setmetatable from bottom of stack to top of stack (negative)
Edit2: It's because I'm trying to have Parent:children act both as a table and as userdata. So I can return userdata with the C object pointer along with the ChildMetaTable with __index to determine what to do with the child methods.
What I was trying to do was to have both a Lua table and userdata at the same time.
First the parent __index method is best replaced by function in the table that creates new userdata for the child object.
static int Parent_children(lua_State * lua)
{
int idx = luaL_checkinteger(lua, -1);
Parent * p = &parent;
luaL_argcheck(lua, (idx >= 0) && (idx < (int)p->children.size()), 1, "index out of range");
Child ** pc = static_cast<Child **>(lua_newuserdata(lua, sizeof(Child *)));
*pc = parent.children[idx];
luaL_getmetatable(lua, "ChildMetaTable"); // [-0, +1, m]
lua_setmetatable(lua, -2);
return 1;
}
static const struct luaL_Reg Parent_MetaList[] = {
{ "__tostring", Parent_tostring },
{ NULL, NULL }
};
Since the child is not a Lua table, the child functions can be called from the __index method. Child_FunctionList stays the same.
static int Child_index(lua_State * lua)
{
const char * fn_name = luaL_checkstring(lua, -1);
for(const luaL_Reg * fn = Child_FunctionList; fn->name != NULL; fn++)
{
if(strcmp(fn_name, fn->name) == 0)
{
lua_pushcfunction(lua, fn->func);
return 1;
}
}
return 0;
}
static const struct luaL_Reg Child_MetaList[] = {
{ "__tostring", Child_name },
{ "__index", Child_index },
{ NULL, NULL }
};
And the child methods get a C pointer from the userdata.
static int Child_name(lua_State * lua)
{
Child * c = *reinterpret_cast<Child **>(luaL_checkudata(lua, -1, "ChildMetaTable"));
lua_pushstring(lua, c->name.c_str());
return 1;
}
And finally registering tables values for the child doesn't make sense, so can be removed but the metatable needs to be registered.
void Child_Register(lua_State * lua)
{
if(luaL_newmetatable(lua, "ChildMetaTable"))
luaL_setfuncs(lua, Child_MetaList, 0);
lua_pop(lua, 1);
}
This may not be the optimal solution, but it is heading there.
Edit:
The global parent can be passed as an upvalue in the luaL_newlib macro is expanded, rather than using the global parent.
luaL_newlibtable(lua, Parent_FunctionList);
lua_pushlightuserdata(lua, parent);
luaL_setfuncs(lua, Parent_FunctionList, 1);
...
static int Parent_children(lua_State * lua) {
Parent * parent= (Parent *)(lua_topointer(lua, lua_upvalueindex(1)));
...
I have an application with several Forms. Two of them are quite similar, they have features in the form of VCL objects (labels, images, etc...) in common, which I named the same.
I want to have a function in a specific class which can accept one of these two Form as a parameter in order to modify the parameters that they have in common. The solution I came around does not seem to work.
As my application is quite big and complicated, I replicated the problem using a small example.
First, below is an example of my MainForm :
And an example of one subForm (they are all arranged in a similar way)
I have an additionnal class which is used to fill in the Edits on the subForms. The code for this class is the following:
#pragma hdrstop
#include "master_class.h"
#include "sub_Form2.h"
#include "sub_Form3.h"
#include "sub_Form4.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
Master::Master(void)
{
}
Master::~Master(void)
{
}
void Master::WriteToForm(TForm* Form)
{
TForm2* curForm = static_cast<TForm2*>(Form);
TForm3* self = dynamic_cast<TForm3*>(Form);
TForm2* self2 = dynamic_cast<TForm2*>(Form);
if (self != NULL && self2 == NULL) {
TForm3* curForm = static_cast<TForm3*>(Form);
}
else if (self == NULL && self2 != NULL) {
TForm2* curForm = static_cast<TForm2*>(Form);
}
curForm -> Edit1 -> Text = "blablabla_1";
curForm -> Edit2 -> Text = "blablabla_2";
}
And in the MainForm, the code for the "Fill Form2" button is the following:
Master1 -> WriteToForm(Form2);
where Master1 is just an object of the Master class.
This works very well for Form2 :
But for Form3, which is filled up using Master1 -> WriteToForm(Form3), here is what I get, which the same pb than in my real application:
So what should go to the Edit, is misplaced. I think the main pb comes from the fact that I did not create every label, edit, etc... on the same order. I did that on purpose to mimic my real application. To verify this, I created a 3rd subForm, where this time the VCL objects were created in the same order as my first subForm, and this works:
So I would suspect that this comes from the initial cast
TForm2* curForm = static_cast<TForm2*>(Form);
When I pass Form3 as an argument, Form3 is somewhat casted into the "shape" of Form2, which is not defined in the same order. Maybe this could be corrected by modifying directly the DFM file, but it is not a realistic approach for my main app.
I do this initial cast otherwise I get a compilation error saying that curForm is not known at the first line
curForm -> Edit1 -> Text = "blablabla_1";
So, is there a better way to pass the Form as an argument to the WriteToForm function?
Just because two types are similar does not mean they are related. Your code does not work because your two Form classes are not related to each other in any way. You can't just cast one to the other arbitrarily.
To solve this, you have several options:
code for both Form classes separately, eg:
void Master::WriteToForm(TForm* Form)
{
TForm2* curForm2 = dynamic_cast<TForm2*>(Form);
TForm3* curForm3 = dynamic_cast<TForm3*>(Form);
if (curForm2)
{
curForm2->Edit1->Text = _D("blablabla_1");
curForm2->Edit2->Text = _D("blablabla_2");
}
else if (curForm3)
{
curForm3->Edit1->Text = _D("blablabla_1");
curForm3->Edit2->Text = _D("blablabla_2");
}
}
Or:
void WriteToForm(TForm2* Form);
void WriteToForm(TForm3* Form);
...
void Master::WriteToForm(TForm2* Form)
{
Form->Edit1->Text = _D("blablabla_1");
Form->Edit2->Text = _D("blablabla_2");
}
void Master::WriteToForm(TForm3* Form)
{
Form->Edit1->Text = _D("blablabla_1");
Form->Edit2->Text = _D("blablabla_2");
}
Make your function use a template (however, be aware of this: Why can templates only be implemented in the header file?):
template<typename T>
void WriteToForm(T* Form);
...
void Master::WriteToForm<T>(T* Form)
{
Form->Edit1->Text = _D("blablabla_1");
Form->Edit2->Text = _D("blablabla_2");
}
make the two Form classes derive from a common base class or interface, eg:
class TBaseForm : public TForm
{
public:
inline __fastcall TBaseForm(TComponent *Owner) : TForm(Owner) {}
virtual void SetEdit1(const String &Text) = 0;
virtual void SetEdit2(const String &Text) = 0;
};
...
class TForm2 : public TBaseForm
{
...
public:
__fastcall TForm2(TComponent *Owner);
...
void SetEdit1(const String &NewText);
void SetEdit2(const String &NewText);
};
__fastcall TForm2::TForm2(TComponent *Owner)
: TBaseForm(Owner)
{
...
}
void TForm2::SetEdit1(const String &NewText)
{
Edit1->Text = NewText;
}
void TForm2::SetEdit2(const String &NewText)
{
Edit2->Text = NewText;
}
...
repeat for TForm3...
...
void Master::WriteToForm(TBaseForm* Form)
{
Form->SetEdit1(_D("blablabla_1"));
Form->SetEdit2(_D("blablabla_2"));
}
Or:
__interface INTERFACE_UUID("{E900785E-0151-480F-A33A-1F1452A431D2}")
IMyIntf : public IInterface
{
public:
virtual void SetEdit1(const String &Text) = 0;
virtual void SetEdit2(const String &Text) = 0;
};
...
class TForm2 : public TForm, public IMyIntf
{
...
public:
__fastcall TForm2(TComponent *Owner);
...
void SetEdit1(const String &NewText);
void SetEdit2(const String &NewText);
};
__fastcall TForm2::TForm2(TComponent *Owner)
: TForm(Owner)
{
...
}
void TForm2::SetEdit1(const String &NewText)
{
Edit1->Text = NewText;
}
void TForm2::SetEdit2(const String &NewText)
{
Edit2->Text = NewText;
}
...
repeat for TForm3...
...
void Master::WriteToForm(IMyIntf* Intf)
{
Intf->SetEdit1(_D("blablabla_1"));
Intf->SetEdit2(_D("blablabla_2"));
}
use RTTI to access the fields, eg:
#include <System.Rtti.hpp>
void Master::WriteToForm(TForm* Form)
{
TRttiContext Ctx;
TRttiType *FormType = Ctx.GetType(Form->ClassType());
TRttiField *Field = FormType->GetField(_D("Edit1"));
if (Field)
{
TValue value = Field->GetValue(Form);
if( (!value.Empty) && (value.IsObject()) )
{
TObject *Obj = value.AsObject();
// Either:
static_cast<TEdit*>(Obj)->Text = _D("blablabla_1");
// Or:
TRttiProperty *Prop = Ctx.GetType(Obj->ClassType())->GetProperty(_D("Text"));
if (Prop) Prop->SetValue(Obj, String(_D("blablabla_1")));
}
}
Field = FormType->GetField(_D("Edit2"));
if (Field)
{
TValue value = Field->GetValue(Form);
if( (!value.Empty) && (value.IsObject()) )
{
TObject *Obj = value.AsObject();
// Either:
static_cast<TEdit*>(Obj)->Text = _D("blablabla_2");
// Or:
TRttiProperty *Prop = Ctx.GetType(Obj->ClassType())->GetProperty(_D("Text"));
if (Prop) Prop->SetValue(Obj, String(_D("blablabla_2")));
}
}
}
I tried do something in a cpp class and when doing the function return callback to swift.
So i do these things :
Creating this function in callbackClass.cpp
int callback::run(void (*callback)(int))
{
for (unsigned int i = 0; i < 100; i++)
{
callback(i);
}
return 0;
}
In callbackClass.hpp :
class callbackClass.hpp
{
.
.
.
public:
int run(void (*callback)(int));
};
#endif
And for header.h :
int callback(void (*callback)(int));
It's good until logging callback in Swift side:
func callbackFunc(){
callback({valueFromCallback in //call cpp function
print(valueFromCallback) //Works fine
})
}
But when try to do other stuff like :
func callbackFunc(){
var value : String!
callback({valueFromCallback in //call cpp function
value = String(valueFromCallback) //It has a problem
})
}
Xcode return this error :
A C function pointer cannot be formed from a closure that captures context
I have already seen these questions but did not help:
Swift: Pass data to a closure that captures context
How to cast self to UnsafeMutablePointer<Void> type in swift
A C function pointer cannot be formed from a closure that captures context
Eventually I realized it possible to pass 'closure' to c++ as argument
So at first I created a Closure in Swift class:
typealias closureCallback = (Int32) -> ()
Then passed it to cpp side :
In header.h
int callback(void (^closureCallback)(int));
In callbackClass.hpp :
class callbackClass.hpp
{
.
.
.
public:
int run(void (^closureCallback)(int));
};
#endif
And in callbackClass.cpp
int callback::run(void (^closureCallback)(int))
{
for (unsigned int i = 0; i < 100; i++)
{
closureCallback(i);
}
return 0;
}
At last handle it in Swift :
typealias closureCallback = (Int32) -> ()
func callbackFunc(){
var value : String!
let closureValue: closureCallback = {valueFromclosureCallback in
value = String(valueFromclosureCallback)
}
callback(closureValue) //call cpp function
}
Having this Repository method
#Query("MATCH (i:`Interest`) WHERE not(i-[:PARENT]->()) return i")
public Page<Interest> findAllByParentIsNull(Pageable pageRequest);
It cause (it didn't respect the specification):
org.springframework.core.convert.ConversionFailedException: Failed to convert from type java.util.LinkedHashSet<?> to type org.springframework.data.domain.Page<?> for value '[com.nearofme.model.Interest#12a4479, com.nearofme.model.Interest#15bdfb3, com.nearofme.model.Interest#1af6067, com.nearofme.model.Interest#1c17d4d, com.nearofme.model.Interest#df65f4, com.nearofme.model.Interest#3b140d, com.nearofme.model.Interest#1e24566, com.nearofme.model.Interest#da49c9]'; nested exception is org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type java.util.LinkedHashSet<?> to type org.springframework.data.domain.Page<?>
at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:192)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:176)
at org.springframework.data.repository.core.support.QueryExecutionResultHandler.postProcessInvocationResult(QueryExecutionResultHandler.java:75)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:439)
Debugging the code shows that a conversion is needed at the GraphRepositoryQuery level :
#Override
public final Object execute(Object[] parameters) {
Class<?> returnType = graphQueryMethod.getMethod().getReturnType();
Class<?> concreteType = graphQueryMethod.resolveConcreteReturnType();
Map<String, Object> params = resolveParams(parameters);
// could be converted here
return execute(returnType, concreteType, getQueryString(), params);
}
The current code convert the result at GraphRepositoryImpl with the private method updatePage that should be used in the GraphRepositoryQuery
#Override
public Page<T> findAll(Pageable pageable, int depth) {
Collection<T> data = session.loadAll(clazz, convert(pageable.getSort()), new Pagination(pageable.getPageNumber(), pageable.getPageSize()), depth);
return updatePage(pageable, new ArrayList<T>(data));
}
So my current temporary solution is to update GraphRepositoryQuery with :
#Override
public final Object execute(Object[] parameters) {
Class<?> returnType = graphQueryMethod.getMethod().getReturnType();
Class<?> concreteType = graphQueryMethod.resolveConcreteReturnType();
Map<String, Object> params = resolveParams(parameters);
Object result = execute(returnType, concreteType, getQueryString(), params);
if (params.size()>0){
Object param = params.values().toArray()[0];
if (param instanceof Pageable){
Pageable pageable = (Pageable) param;
result = updatePage(pageable, new ArrayList((Collection) result));
}
}
return result;
}
private Page updatePage(Pageable pageable, List results) {
int pageSize = pageable.getPageSize();
int pageOffset = pageable.getOffset();
int total = pageOffset + results.size() + (results.size() == pageSize ? pageSize : 0);
return new PageImpl(results, pageable, total);
}
No more need to convert inside the GraphRepositoryImpl but it still working