2

I'm trying to wrap C++ objects for use in javascript as per the node.js documentation here: https://nodejs.org/api/addons.html#addons_wrapping_c_objects

The Addon would build without error, and work properly when my object "AnObject" only had numeric attributes i.e "int32_t age;".

When I added the attribute "std::string name;" to AnObject, "node-gyp configure" worked, however "node-gyp build" gave the following error:

Wills-MacBook-Pro:cppObjectWrapping willalley$ node-gyp build
[...]
In file included from ../personAddon.cc:3:
../AnObject.h:24:21: error: implicit instantiation of undefined template 
'std::basic_string<char, std::char_traits<char>,
      std::allocator<char> >'
        std::string name;
                    ^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs
/MacOSX10.12.sdk/usr/include/c++/4.2.1/bits/stringfwd.h:56:11: note: 
      template is declared here
    class basic_string;
          ^
1 error generated.
[...]
Wills-MacBook-Pro:cppObjectWrapping willalley$

Here is my objects header file where the error is thrown, AnObject.h:

    #pragma once

    #include <node.h>
    #include <node_object_wrap.h>
    #include <string.h>

    namespace demo {

        class AnObject : public node::ObjectWrap {
        public:
            static void Init(v8::Local<v8::Object> exports);

        private:
            explicit AnObject(int32_t num = 19);
            ~AnObject();

            static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
            static void setAge(const v8::FunctionCallbackInfo<v8::Value>& args);
            static void getAge(const v8::FunctionCallbackInfo<v8::Value>& args);
            static void setName(const v8::FunctionCallbackInfo<v8::Value>& args);
            static void getName(const v8::FunctionCallbackInfo<v8::Value>& args);
            static v8::Persistent<v8::Function> constructor;
            int32_t age;
            std::string name;
        };

    }  // namespace demo

and if you're curious, the implementation file AnObject.cc:

#include "AnObject.h"
#include <string.h>

namespace demo {

    using v8::Context;
    using v8::Function;
    using v8::FunctionCallbackInfo;
    using v8::FunctionTemplate;
    using v8::Isolate;
    using v8::Local;
    using v8::Number;
    using v8::Object;
    using v8::Persistent;
    using v8::String;
    using v8::Value;

    Persistent<Function> AnObject::constructor;

    AnObject::AnObject(int32_t age_) : age(age_) {
    }

    AnObject::~AnObject() {
    }

    void AnObject::Init(Local<Object> exports) {
        Isolate* isolate = exports->GetIsolate();

        // Prepare constructor template
        Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
        tpl->SetClassName(String::NewFromUtf8(isolate, "AnObject"));
        tpl->InstanceTemplate()->SetInternalFieldCount(1);

        // Prototype
        NODE_SET_PROTOTYPE_METHOD(tpl, "setAge", setAge);
        NODE_SET_PROTOTYPE_METHOD(tpl, "setName", setName);
        NODE_SET_PROTOTYPE_METHOD(tpl, "getAge", getAge);
        NODE_SET_PROTOTYPE_METHOD(tpl, "getName", getName);

        constructor.Reset(isolate, tpl->GetFunction());
        exports->Set(String::NewFromUtf8(isolate, "AnObject"),
                     tpl->GetFunction());
    }

    void AnObject::New(const FunctionCallbackInfo<Value>& args) {
        Isolate* isolate = args.GetIsolate();

        if (args.IsConstructCall()) {
            // Invoked as constructor: `new AnObject(...)`
            int32_t value = args[0]->IsUndefined() ? 0 : args[0]->Int32Value();;
            AnObject* obj = new AnObject(value);
            obj->Wrap(args.This());
            args.GetReturnValue().Set(args.This());
        } else {
            // Invoked as plain function `AnObject(...)`, turn into construct call.
            const int argc = 1;
            Local<Value> argv[argc] = { args[0] };
            Local<Context> context = isolate->GetCurrentContext();
            Local<Function> cons = Local<Function>::New(isolate, constructor);
            Local<Object> result =
            cons->NewInstance(context, argc, argv).ToLocalChecked();
            args.GetReturnValue().Set(result);
        }
    }

    void AnObject::setAge(const FunctionCallbackInfo<Value>& args) {
        Isolate* isolate = args.GetIsolate();
        AnObject* obj = ObjectWrap::Unwrap<AnObject>(args.Holder());
        if (args[0]->IsInt32()){
            obj->age = args[0]->Int32Value();
            args.GetReturnValue().Set(Number::New(isolate, obj->age));
        }
    }

    void AnObject::setName(const v8::FunctionCallbackInfo<v8::Value>& args) {
        Isolate* isolate = args.GetIsolate();
        AnObject* obj = ObjectWrap::Unwrap<AnObject>(args.Holder());

        if (args[0]->isString()) {
            std::string input(*v8::String::Utf8Value(args[0]->ToString()));
            obj->name = input;
            args.GetReturnValue().Set(Number::New(isolate, obj->name));
        }
    }

    void AnObject::getAge(const FunctionCallbackInfo<Value>& args) {
        Isolate* isolate = args.GetIsolate();
        AnObject* obj = ObjectWrap::Unwrap<AnObject>(args.Holder());
        args.GetReturnValue().Set(Number::New(isolate, obj->age));
    }

    void AnObject::getName(const FunctionCallbackInfo<Value>& args) {
        Isolate* isolate = args.GetIsolate();
        AnObject* obj = ObjectWrap::Unwrap<AnObject>(args.Holder());
        v8::Local<v8::String> output = v8::String::NewFromUtf8(isolate, name.cstr());
        args.GetReturnValue().Set(Number::New(isolate, output));
    }

}  // namespace demo
4
  • Looks your "compiler" doesn't know about the std::string class from the C++ standard library... Commented Nov 11, 2016 at 1:14
  • Maybe look for v8::String Commented Nov 11, 2016 at 1:15
  • Don't edit the solution into your question. Answer your own question instead. Commented Nov 11, 2016 at 2:20
  • Sorry @dorukayhan, first time posting a question! Commented Nov 11, 2016 at 2:24

1 Answer 1

2

The face-palm worthy solution I found is:

change:

#include <string.h>

to:

#include <string>

in both AnObject.h and AnObject.cc

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.