0

I decided to try creating a simple C wrapper for the V8 API using the model described in Developing C wrapper API for Object-Oriented C++ code. Unfortunately, I'm not too familiar with C++, so I'm running into an issue with inherited constructors.

v8capi.h

typedef struct V8Context V8Context;

#ifdef __cplusplus
extern "C" {
#endif

V8Context *V8_NewContext();

#ifdef __cplusplus
}
#endif

v8capi.cpp

#include <v8.h>

struct V8Context : public v8::Handle<v8::Context> { };

V8Context *V8_NewContext() {
    v8::HandleScope hscope;
    return new V8Context(v8::Context::New());
}

From what I understand, new V8Context(...) should call v8::Handle<T>'s constructor which takes a Handle<T>. v8::Context::New() returns a v8::Persistent<T>, which inherits v8::Handle<T>, so that should work. But in reality, it's trying to call a constructor that takes a const V8Context &:

error C2664: 'V8Context::V8Context' : cannot convert parameter 1 from
'v8::Persistent<T>' to 'const V8Context &'
    with
    [
        T=v8::Context
    ]
    No user-defined-conversion operator available that can perform this
    conversion, or the operator cannot be called

What am I doing wrong?

Community
  • 1
  • 1
David Brown
  • 35,411
  • 11
  • 83
  • 132
  • I'm not familiar with V8. But from the looks of it, it seems it highly exploits the strengths of C++ and that "extracting a nice C interface" is somewhere between impossible and hard. In C you would not be able to benefit from the HandleScope and Local<> handle stuff at all. You're forced to using additional layers of indirection (yuck). Consider learning C++ maybe? – sellibitze Jan 12 '12 at 18:08
  • Yes, I think wrapping the entire API would be difficult, but I just used Context as an example. I'm probably just going to implement the minimum functionality needed to register functions and set/get properties so that the VM can be initialized in C++, but loadable modules can be written in C. If I need to hold on to a handle outside of its local scope, I can just convert it to a Persistent (that's how I understand it, at least). – David Brown Jan 12 '12 at 20:02

5 Answers5

1

There is no constructor defined in V8Context, so only the implicit copy constructor appears as an option. You need to explicitly define a constructor in V8Context that forwards the v8::Persistent<T> argument to its base class.

thiton
  • 35,651
  • 4
  • 70
  • 100
  • I see, thank you. I was confused by the fact that the example in the link I provided didn't implement a constructor in the struct. So I assumed it was inherited. – David Brown Jan 12 '12 at 17:44
0

Constructors aren't inherited in C++ (although there are some passthrough features in C++11 I believe), so you're going to have to write your own constructor in V8Context that explicitly calls the proper base class constructor.

Mark B
  • 95,107
  • 10
  • 109
  • 188
0

From what I understand, new V8Context(...) should call v8::Handle<T>'s constructor.

new V8Context(...) will only call a constructor declared in V8Context; constructors are not inherited. You'll need to add one, something like:

V8Context(v8::Handle<v8::Context> const & handle) : 
    v8::Handle<v8::Context>(handle) 
{}
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
0

new V8Context(...) doesn't call a constructor from v8::Handle<T>, but a constructor from V8Context. Since you haven't defined one, only the default constructor and copy constructor are availible (constructors aren't inheritable). Therefore it tries to call the copy constructor and fails since the argument can't be converted to V8Context. To solve your problem you need to add an appropriate constructor to V8Context, which forwards the argument to the base constructor (might not be the exact code given, depending how excatly your arguments look like, but similar):

struct V8Context : public v8::Handle<v8::Context> {
  V8Context(const v8::Handle<v8::Context>& handle): v8::Handle<v8::Context>(handle) {}
};
Grizzly
  • 19,595
  • 4
  • 60
  • 78
0

Your V8Context only has the compiler generated constructors:

  • the copy constructor which is synthesized whenever it is needed and not explicitly declared or made impossible (e.g. by deriving from a class without a copy constructor). This constructor take a V8Cintext as argument.
  • the default constructor which is synthesized when needed, when there is no explicit constructor, and all members and bases can be default constructed. Thos constructor has no arguments.

It seems the type you try to pass doesn't match the signature of the copy constructor. If you want to use it you'll need to explicitly provide a corresponding constructior.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380