How to bind a std::map to Lua with LuaBind - c++

I'm trying to expose my std::map<std::string, std::string> as a class property to Lua. I've set this method for my getter and setter:
luabind::object FakeScript::GetSetProperties()
{
luabind::object table = luabind::newtable(L);
luabind::object metatable = luabind::newtable(L);
metatable["__index"] = &this->GetMeta;
metatable["__newindex"] = &this->SetMeta;
luabind::setmetatable<luabind::object, luabind::object>(table, metatable);
return table;
}
This way it makes me able to do something like this in Lua:
player.scripts["movement"].properties["stat"] = "idle"
print(player.scripts["movement"].properties["stat"])
However, the code I've provided in C++ doesn't getting compiled. It tells me there is an ambiguous call to overloaded function at this line metatable["__index"] = &this->GetMeta; and the line after it. I'm not sure that I'm doing this correctly.
Error message:
error C2668: 'luabind::detail::check_const_pointer' :
ambiguous call to overloaded function
c:\libraries\luabind-0.9.1\references\luabind\include\luabind\detail\instance_holder.hpp 75
These are SetMeta and GetMeta in FakeScript:
static void GetMeta();
static void SetMeta();
Previously I was doing this for getter method:
luabind::object FakeScript::getProp()
{
luabind::object obj = luabind::newtable(L);
for(auto i = this->properties.begin(); i != this->properties.end(); i++)
{
obj[i->first] = i->second;
}
return obj;
}
This works fine, but it's not letting me to use setter method. For example:
player.scripts["movement"].properties["stat"] = "idle"
print(player.scripts["movement"].properties["stat"])
In this code it just going to trigger getter method in both lines. Although if it was letting me to use setter, I wouldn't be able to get key from properties which it is ["stat"] right here.
Is there any expert on LuaBind here? I've seen most of people say they've never worked with it before.

You need to use the (undocumented) make_function() to make objects from functions.
metatable["__index"] = luabind::make_function(L, &this->GetMeta);
metatable["__newindex"] = luabind::make_function(L, &this->GetMeta);
Unfortunately, this (the simplest) overload of make_function is broken, but you just need to insert f as the second parameter in make_function.hpp.

Related

How does passing Objective-C object as argument to C++ method work?

I was reading source code of WebKit yesterday when I found some lines of code that I can't understand how it works.
There is a C++ method declared in WebPageProxy.h as this:
RefPtr<API::Navigation> loadRequest(const WebCore::ResourceRequest&, WebCore::ShouldOpenExternalURLsPolicy = WebCore::ShouldOpenExternalURLsPolicy::ShouldAllowExternalSchemes, API::Object* userData = nullptr);
It is called in WKWebView.mm like this:
- (WKNavigation *)loadRequest:(NSURLRequest *)request
{
auto navigation = _page->loadRequest(request);
if (!navigation)
return nil;
return [wrapper(*navigation.leakRef()) autorelease];
}
The argument request is of type NSURLRequest *, but the type in the declaration of the method is const WebCore::ResourceRequest&. I can't fully understand it.
Also, after setting some breakpoints and experimenting, I found that this constructor of the ResourceRequest class is being called:
ResourceRequest(NSURLRequest *nsRequest)
: ResourceRequestBase()
, m_nsRequest(nsRequest)
{
}
I'm not familiar with C++. Can someone help me understand how does this work?

How to get a member function pointer in MSVC?

I'm not going to get into too much of the details on the Excel side of things, I essentially took code from this example:
C++ app automates Excel (CppAutomateExcel)
solution1.cpp
So I've tried this code in MSVC and it compiles:
class foo { public: virtual void bar(){} };
int main()
{
void (foo::*p)() = &foo::bar;
}
But similar code to capture the address of the move function in Excel does not work:
int main()
{
Excel::_ApplicationPtr spXlApp;
HRESULT hr = spXlApp.CreateInstance(__uuidof(Excel::Application));
Excel::WorkbooksPtr spXlBooks = spXlApp->Workbooks;
Excel::_WorkbookPtr spXlBook = spXlBooks->Add();
Excel::_WorksheetPtr spXlSheet = spXlBook->ActiveSheet;
HRESULT(Excel::_Worksheet::*pMove)(...) = &spXlSheet->Excel::_Worksheet::Move;
<... irrelevant code ...>
return 0;
}
This has the following compiler error:
error C2276: '&': illegal operation on bound member function expression
If I remove the &, it says I should add it back:
error C3867: 'Excel::_Worksheet::Move': non-standard syntax; use '&' to create a pointer to member
Any help on what to do here would be greatly appreciated.
You say in your question "but similar code..." and then you show code in which you do not do the same thing. Try using the same syntax for setting pMove as you used for setting p in your smaller example. Try something like &Excel::_Worksheet::Move; (without the "spXlSheet->").
If you can specify the specific instance of the object for which to call the function pointer at the time that you set the function pointer as you have there, I'm not aware of such a capability. After dropping spXlSheet-> from where you set the variable, use it instead where you want to call the function pointer.
You need to declare the method pointer like this instead:
// or whatever parameter type Move() actually uses...
void (Excel::_Worksheet::*pMove)(tagVARIANT, tagVARIANT) = &Excel::_Worksheet::Move;
Then, to actually call pMove(), you would have to do something like this:
Excel::_WorksheetPtr spXlSheet = ...;
(spXlSheet.Get()->*pMove)(...);

Initialization of std::function does not evaluate to a function taking 3 arguments

GameObject class .h + .cpp:
typedef std::function<void(GameObject* triggerobject, GameObject* otherobject, TriggerAction action)> PhysicsCallback;
void GameObject::OnTrigger(GameObject* triggerobject, GameObject* otherobject, TriggerAction action)
{
if (m_OnTriggerCallback)
m_OnTriggerCallback(triggerobject, otherobject, action);
}
void GameObject::SetOnTriggerCallBack(PhysicsCallback callback)
{
m_OnTriggerCallback = callback;
}
Other class:
m_pSphere->SetOnTriggerCallBack(*pCbObj);
m_pSphere->OnTrigger(m_pWallLeft, m_pSphere, GameObject::TriggerAction(0));
I figured to use the OnTrigger() function I had to set m_OnTriggerCallback. When I tried to pass corresponding arguments however I got really stuck. It seems almost impossible to initalize PhysicsCallback without getting compiler errors.
I tried:
std::function<void(GameObject* triggerobject, GameObject* otherobject, GameObject::TriggerAction action)> *obj;
*obj = (m_pWallRight, m_pSphere, GameObject::TriggerAction(0));
But no luck. *obj doesn't accept any arguments. These following lines give the same errors:
GameObject::PhysicsCallback *pCbObj; = new GameObject::PhysicsCallback(new std::function<void()>()); //term does not evaluate to a function taking 3 arguments
GameObject::PhysicsCallback *pCbObj = new GameObject::PhysicsCallback((m_pWallRight, m_pSphere, GameObject::TriggerAction(0)));
And this line *pCbObj = GameObject::PhysicsCallback(m_pWallRight, m_pSphere, GameObject::TriggerAction(0));gives this intellisense error:
http://puu.sh/gi29n/95f0f7855b.png
I'm really confused, how to use the SetOnTriggerCallBack function?
Doing
m_pSphere->OnTrigger(m_pWallLeft, m_pSphere, GameObject::TriggerAction(0));
is actually calling GameObject::TriggerAction with 0 as argument. Then, it passes its result.
What is GameObject::TriggerAction? Is it a static method ? It should be because, otherwise, you have either to std::bind it to an object instance or to apply it directly.
With a lambda I was able to create an parameter that was acceptable for the compiler:
GameObject::PhysicsCallback trigger = [=](GameObject* triggerobject, GameObject* otherobject, GameObject::TriggerAction action){};

Add members dynamically to a class using Lua + SWIG

This Lua code, creates a table and dynamically adds a new member. Running this I can get "hello" on the screen as expected:
foo = {}
foo.x = "hello"
print(foo.x)
But now I'm using SWIG to bind some C++ classes to Lua.
For that purpose, in a test.i (SWIG module file) I created a simple class like this:
%module test
%inline
%{
class Foo
{
public:
Foo() { X = 0; }
void SetX(int x) { X = x; }
int GetX() { return X; }
private:
int X;
};
%}
Then I wrote a test Lua code like that:
obj = test.Foo()
obj:SetX(5)
print("Number: " .. obj:GetX())
Running and getting "Number 5" as expected. The problem is that when I dynamically add a new member to my SWIG-binded object, and I try to access it, like so:
obj.Y = 7
print("Number: " .. obj.Y)
I get this error message:
"attempt to concatenate field 'Y' (a nil value)"
Is it possible to dynamically add new members on objects binded using SWIG? Is there some option without having to move to another Lua binding library?
SWIG doesn't use tables for its objects; it uses userdata. After all, those objects are C++ objects, and need to store C++ data that Lua code shouldn't be able to touch.
And I wouldn't bother looking for "another Lua binding library"; pretty much all of them use userdata, which Lua code explicitly cannot modify (in order to provide the ability to do exactly this).
However, that doesn't mean you can't cheat.
You can always wrap the object you get from C++ code into your own Lua table, which would have a metatable that forwards unknown calls to the C++ object. The code to do so would look something like this:
local function WrapObject(cppObject)
local proxy = {}
local wrapper_metatable = {}
function wrapper_metatable.__index(self, key)
local ret = rawget(self, key)
if(not ret) then
ret = cppObject[key]
if(type(ret) == "function") then
return function(self, ...)
return ret(cppObject, ...)
end
else
return ret
end
else
return ret
end
end
setmetatable(proxy, wrapper_metatable)
return proxy
end
The returned proxy object is a Lua table that can have keys and values set on it. When you get a value, such as to call a function, it will see if that value was set in the table. If not, it attempts to fetch it from the C++ object that you wrapped, which will go through its metatable.
You'll need to expand this metatable if your C++ class uses other metafunctions like __add, __sub, __tostring and so forth.

C++11 Lambda Functions inside member methods inherit scope

I've written a function foreach that accepts a lambda function ala:
void foreach(void (*p)(pNode))
{ /* ... */ }
Which works as intended if I pass a lambda function from the main loop:
int a = 5;
env.N().foreach
(
[&](pNode n)->void
{
n->tps(a);
}
);
However, if I try to call the same function from within a member method, the lambda function "inherits" the scope of the member function and generates a compiler error. For example, if I try to include it inside the member method of class Object named method(), I get the following error:
error: no matching function for call to ‘IDSet<Node>::foreach(Object::method()::<lambda(pNode)>)’
note: candidate is: void IDSet<T>::foreach(void (*)(IDSet<T>::pT)) [with T = Node, IDSet<T>::pT = pNode]
I realize this is the compiler being safe, since I could include instance-specific variables inside the lambda function, in which case the lambda would need to be scoped, however I'm wondering if it's possible to make this lambda "static".
I've tried a reinterpret_cast, however that gives me this error:
error: invalid cast from type ‘Object::method()::<lambda(pNode)>’ to type ‘void (*)(pNode)’
Specifying static before [&](pNode ... doesn't seem like valid syntax either.
Desperately, I also tried changing [&] to [=], [], [a], none of which worked.
Does anyone know if there is a way to do accomplish my goal of creating a "static" lambda function, or at any sort of lambda function that will be accepted for that matter?
Thanks!
Answer:
With help from Cat Plus Plus, I was able to turn my incorrect code:
void foreach(void (*p)(pT))
{
for(pTiter i = _map.begin(); i != _map.end(); i++)
{
(*p)(i->second);
}
}
into fully functional code:
void foreach(std::function<void(pT)>(p))
{
for(pTiter i = _map.begin(); i != _map.end(); i++)
{
p(i->second);
}
}
that does what I was looking for perfectly.
Well, you can not use pointers.
void foreach(std::function<void(pNode)>);