I am trying to create a basic native node addon where a javascript array is passed from node and then processed in c++. The problem is I cannot figure out how to correctly pass the array. I can instantiate the array without issue but assigning it using info[0].as throws errors.
My c++ code is
#include <napi.h>
using namespace Napi;
using namespace std;
Value Add(const CallbackInfo& info)
{
Env env = info.Env();
Array result = Napi::Array::New(env);
Array a = info[0].As<Array>;
double arg1 = info[1].As<Number>().DoubleValue();
Number num = Napi::Number::New(env, 2 + arg1);
return num;
}
The error I am getting is
../cppsrc/main.cpp: In function ‘Napi::Value Add(const Napi::CallbackInfo&)’:
../cppsrc/main.cpp:12:21: error: conversion from ‘<unresolved overloaded function type>’ to non-scalar type ‘Napi::Array’ requested
Array a = info[0].As<Array>;
~~~~~~~~^~~~~~~~~
What is the correct way to pass an array to c++? Is it even possible?
This works for me:
void runSetPropertyAsyncWorker(const CallbackInfo& info)
{
std::string path = info[0].As<Napi::String>();
int property = info[1].As<Number>();
int dataSize = info[2].As<Number>();
Array b = info[3].As<Array>();
for(int i = 0; i<b.Length(); i++)
{
Napi::Value v = b[i];
if (v.IsNumber())
{
int value = (int)v.As<Napi::Number>();
...
...
}
}
...
...
Function callback = info[4].As<Function>();
AsyncWorker* asyncWorker = new SetPropertyAsyncWorker(callback, ...);
asyncWorker->Queue();
}
Use Napi::Object. Napi::Array is actually inherited from Napi::Object.
You could replace the code Array a = info[0].As<Array>; with Array a = info[0].ToObject();.
You can then access the data members via Value
operator[] (uint32_t index) const
Source: https://nodejs.github.io/node-addon-api/class_napi_1_1_object.html
Edit: Bonus feature, if an argument that is not an object is passed, this will automatically trigger an Error: Object Expected.
error code here:
Array a = info[0].As<Array>;
which should be
Array a = info[0].As<Array>();
I was not able to find a solution to the actual question of interacting with the Javascript object directly with node-addon-api. The Solution that I chose to go with is JSON.stringify any arrays or objects and then parse then in c++ is a library called rapid json. This proves to be the only way to interface with javascript objects that i've been able to find
Related
so this is about an assignment.
I have a header file with predefined ENUM type (TDay) which I CANNOT change in any way. TDay does not support any operator other than streams.
My problem is I need to find a way to do something like this:
Object::Object (uint aSize) {
Object temp; // contains varible inicialized to zero, this variable can be bool, int, RGB structure
// or TDay enum. I also can't use templates here.
for (int i = 0; i < aSize; i++) {
this->array[i] = temp.Value() + 1; // array is of the same type as Value
}
}
This code is just for illustration of what I need to do, don't look for any use of this I just made it up just to better explain my problem.
So anyway this doesn't work because my TDay doesn't support TDay+int operator.
Is there any way around this? Solution doesn't have to be clean, I'll accept any pointer cheats.
EDIT:
So I tried putting in my Object.cpp file this:
TDay operator+(TDay aDay, int aValue) {
return static_cast<TDay>(int(aDay) + aValue);
}
And it doesn't work. Compiler error says:
Argument of type int is imcompatible with parameter of type TDay
However if I put this code to TDay.h it works fine. Is something wrong with my linker?
I would create a function taking current ENUM value named for example increase
void increase(your_enum& e){
if(e == e::MAX_VAL)
e = e::MIN_VAL; //if you have it, otherwise do same as below
else{
int val = int(e); //cast it to int
val++;
e = static_cast<your_enum>(val); //cast it back
}
}
Creating a function taking another parameter to increase/decrease by more than one should be easy from this point.
I'm having a small problem which I can't wrap my head around.
I have a function that looks like this:
template <typename T>
std::unique_ptr<Environment>& CreateEnvironment(sf::Vector2f& _position, bool _addToStatic = false);
This is my function pointer typedef
typedef std::unique_ptr<Environment>& (WorldEditor::*CreateEnvironmentPtr)(sf::Vector2f&, bool);
std::map<std::string,CreateEnvironmentPtr> listEnv;
And I'm trying to simply do this:
listEnv["test"] = &CreateEnvironment<Coin>(sf::Vector2f(200,200), false);
And i get the following error:
error C2440: '=' : cannot convert from 'std::unique_ptr<_Ty> *' to
'std::unique_ptr<_Ty> &(__thiscall WorldEditor::* )(sf::Vector2f
&,bool)'
I understand what the error is saying, but I don't know how to solve it. Also why does it even care about the return type when I'm pointing to the address of the function?
Best regards
nilo
problems such as these are often much better solved with std::function
std::map<std::string, std::function<void()> listEnv;
listEnv.emplace("test", [] {
CreateEnvironment<Coin>(sf::Vector2f(200,200), false);
});
to call:
listEnv.at("test")->second();
Based on your post I am not sure if you are attempting to create the member function pointer and map inside the CreateEnvironment class or outside of it, so I'll solve what I think is the more difficult problem of pointer to a separate object's member function.
I simplified your classes like so:
Environment
struct Environment
{
int i = 1;
};
Coin
struct Coin
{
int k = 0;
};
WorldEditor
struct WorldEditor
{
template <typename T>
std::unique_ptr<Environment> CreateEnvironment(int& _j, bool _addToStatic = false)
{
return std::make_unique<Environment>();
}
};
Solution: Map an object's member fn pointer, and then call it later
(I will be using C++11/14 syntax in my answer)
//declare a pointer to member function in WorldEditor
using CreateEnvironmentPtr = std::unique_ptr<Environment> (WorldEditor::*)(int&, bool);
//declare an object of type WorldEditor, because member function pointers need a "this" pointer
WorldEditor myWorldEditor;
int myInt = 42;
//map a string to the CreateEnvironment<Coin> function
std::map<std::string, CreateEnvironmentPtr> listEnv;
listEnv["test"] = &WorldEditor::CreateEnvironment<Coin>;
// call the member function pointer using the instance I created, as well as
// the mapped function
(myWorldEditor.*listEnv["test"])(myInt, false);
// (printing member value to cout to show it worked)
std::cout << (myWorldEditor.*listEnv["test"])(myInt, false)->i << std::endl; // prints 1
Live Demo
Solution 2: use std::bind and std::function
Perhaps we already know the parameters to the member function call at the time we create the entry for map. Using std::bind with a std::function will help us achieve that (Similar to Richard Hodges' solution):
// now our "function pointer" is really just a std::function that takes no arguments
using CreateEnvironmentPtr = std::function<std::unique_ptr<Environment>(void)>;
//declare an object of type WorldEditor, because member function pointers need a "this" pointer
WorldEditor myWorldEditor;
int myInt = 42;
//map a string to that function pointer
//ensure it gets called with the right args
// by using std::bind (which will also make the arg list appear the be void at call time)
// note that std::bind needs an instance of the class immediately after
// listing the function it should be binding
// only afterwards will we then pass the int& and bool
std::map<std::string, CreateEnvironmentPtr> listEnv;
listEnv["test"] = std::bind(&WorldEditor::CreateEnvironment<Coin>, &myWorldEditor, myInt, false);
// the mapped function
listEnv["test"]()->i;
// (printing resulting unique_ptr<Environment>'s member to cout to show it worked)
std::cout << listEnv["test"]()->i << std::endl; // prints 1
Live Demo 2
I am currently working on an dynamic memory container.
Basic idea of the class is that you should be able to get the iterator of an object if you really do not know it, without the use of a for loop throughout all the elements to boost performance. The issue I have is the following; when you pass your pointer address to the object you want to get the iterator of it type casts the object into the extended memory containers structures type. This type contains an extra element, an integer. (IteratorNum)
When following the code the integer within the function is set to correct value, as below would be 50. But when the returned value is set into the local integer used in the main function it is 200? I've been adding watches and cannot figure out how it is possible that the function returns 50 but value gets set to 200.
template <typename DataType> class MemoryContainer {
public:
struct LevelData : DataType
{
int element;
};
DataType &New()
{
elements++;
//Reallocate the size of the array
ld = (LevelData*)realloc(ld, sizeof(LevelData) * elements);
//Set the iteratorNumber
ld[elements - 1].element = elements - 1;
return ld[elements - 1];
}
DataType *reserve(int num)
{
return calloc(num, sizeof(DataType));
}
DataType &operator[](int i)
{
return ld[i];
}
bool inArray(DataType *type)
{
//Compare memory addresses and see if it's within.
return (type >= &ld[0]) && (type < &ld[elements - 1]);
}
static unsigned int getIterator(DataType *type)
{
// v this is 50, but in main says returns 200.
return ((LevelData*)type)->element;
}
MemoryContainer()
{
elements = 0;
}
~MemoryContainer()
{
free(data);
}
private:
unsigned int elements;
LevelData *ld;
};
struct Effective
{
//Set it to polymorphic classes
virtual void dummy()
{
}
char * testvar;
Effective(char * c)
{
testvar = c;
}
Effective(){}
};
MemoryContainer<Effective> myContainer;
int _tmain(int argc, _TCHAR* argv[])
{
//Create 200 elements in the array
for(int i = 0; i < 200; i++)
myContainer.New().testvar = "E";
//Add pointer for testing purposes to get the iterator.
Effective * pointer = &myContainer[50];
//Test setting it's value
pointer->testvar = "HEHEHE";
//Get iterator of our pointer in the array
unsigned int i = myContainer.getIterator(pointer);
printf(pointer->testvar);
system("PAUSE");
return 0;
}
I suspect it is the visual studio debugger getting confused between your two i variables. If you print out the value of i, it will print correctly. If you change the name of your variable to something else, the value shows as 50 in the debugger.
That said, your code is a mish-mash of c and c++ and won't work correctly with anything that requires a copy constructor. I would suggest at the very least using new [] rather than realloc.
Also, any user of this collection who tries to store a class with a member variable called element is going to get mighty confused.
The unsigned int i in the main function really has a value of 50, but the debugger is confusing it with the i declared in the for loop (I reproduced this with Visual Studio 2013). If you cout i it will be 50, and if you change the variable name it will show up as 50 in the debugger. I've never seen this problem before so I wonder if it might be due to your use of malloc/realloc/free with C++ objects.
So I've got
set<MyClass> mySet;
and in MyClass I have a static int to count the number of compares that happen. I'm trying to get that information out of it but I can't figure out how.
This is what I've tried:
set<MyClass>::iterator it = mySet.begin();
int count = it->getCompareCount();
and
int count = mySet.begin()->getCompareCount();
Neither of those work (Yes I know the are essentially the same exact thing) but I can get that information out of something that is indexed like a std::list or std::vector
Example:
vector<MyClass> myVector;
for (int i = 0; i < 10; i ++)
{
myVector.push_back(MyClass(i,"Some Name", i*2);
}
int count = myVector.at(2).getCompareCount(); //which by default is going to be 0 as no compares have taken place
Can anybody help me? netbeans says "error: passing ‘const MyClass’ as ‘this’ argument of ‘int MyClass::getCompareCount()’ discards qualifiers [-fpermissive]" when I do what I said I tried up above.
EDITS
Declaration of getCompareCount():
int MyClass::getCompareCount()
{
return compareCount;
}
Element in std::set is not mutable after it is inserted into the set. When you dereference an iterator (as in it->), it returns a const reference of the object you put into the set. On the other hand, your definition of getCompareCount() is a non-const instance function meaning it can only be called on non-const instance of the class. Define the function as the following should solve your problem.
int MyClass::getCompareCount() const
{
return compareCount;
}
By the way, since compareCount is a static int, you might want to define the function as static as well so that you can call it using the class instead of having to get an instance to call it.
static int MyClass::getCompareCount()
{
return compareCount;
}
//To Call it
MyClass::getCompareCount()
I have native C++ class SrcClass containing the following:
std::vector<shotEntry> objectsQueue;
bool getRelatedEntry(const entryToProcess *entriesDeets, int &i) const {
if (i >= (int)objectsQueue.size()) {
i = 0;
return false;}
if (!objectsQueue.size()) return false;
entriesDeets = &(objectsQueue[i++]);
return true;
}
In my client I have:
const entryToProcess *entriesDeets = NULL;
int i = 0;
while (srcObj->getRelatedEntry(entriesDeets, i)) {
When I step through getRelatedEntry the formal parameter, entriesDeets is updated as expected before returning. When it returns the actual parameter of the client is not updated.
This is in some big project I have returned to after two months away. I'm pretty sure the last refactoring I did was to introduce these damnable vectors. It takes ages to compile when I mess with headers. Am I getting confused with the initialize once/ readonly/ const'ness of C#? Can I get away with the client getting a read only native object back?
This is because you are setting the value of the function's parameter. You want:
bool getRelatedEntry(const entryToProcess **entriesDeets, int &i) const {
...
*entriesDeets = &(objectsQueue[i++]);
...
and
srcObj->getRelatedEntry(&entriesDeets, i)
entriesDeets is a local variable inside getRelatedEntry. You only modified the local, you didn't affect the value passed in. You need to pass a reference to pointer or a pointer to pointer.
The pointer is updated, but it is the internal copy inside the function. If you want that change to be visible outside of the function, you should pass a reference:
// v
bool getRelatedEntry(const entryToProcess *&entriesDeets, int &i) const {
Or in C style a double pointer and dereference it internally on every usage:
// v
bool getRelatedEntry(const entryToProcess **entriesDeets, int &i) const {
// ...
*entriesDeets = &(objectsQueue[i++]);