1

I have several very similar functions:

v8::Handle<v8::Value> jsAudioPlay(const v8::Arguments &args) {
    Audio *audio = static_cast<Audio*>(args.This()->GetPointerFromInternalField(0));
    if (audio != NULL) audio->play(get(args[0], 0));
    return args.This();
}

v8::Handle<v8::Value> jsAudioPause(const v8::Arguments &args) {
    Audio *audio = static_cast<Audio*>(args.This()->GetPointerFromInternalField(0));
    if (audio != NULL) audio->pause();
    return args.This();
}

v8::Handle<v8::Value> jsAudioLoop(const v8::Arguments &args) {
    Audio *audio = static_cast<Audio*>(args.This()->GetPointerFromInternalField(0));
    if (audio != NULL) audio->loop(get(args[0], -1));
    return args.This();
}

v8::Handle<v8::Value> jsAudioVolume(const v8::Arguments &args) {
    Audio *audio = static_cast<Audio*>(args.This()->GetPointerFromInternalField(0));
    if (audio != NULL) audio->volume(get(args[0], 1.0f));
    return args.This();
}

And I've been reading about C++ templates for hours and I'm convinced that it's possible to get rid of these functions and replace them with templates. I envision the end result will be something like:

typedef Handle<Value> (*InvocationCallback)(const Arguments& args);

template <class T> InvocationCallback FunctionWrapper ...;
template <class T> FunctionWrapper FunctionReal ...;
template <class T, class arg1> FunctionWrapper FunctionReal ...;
template <class T, class arg1, class arg2> FunctionWrapper FunctionReal ...;

I realize similar questions have been asked, but I can't find an example of a template within a template like the above.


Update on 7/21/2012

Template:

template <class T> v8::Handle<v8::Value> jsFunctionTemplate(const v8::Arguments &args) {
    T *t = static_cast<T*>(args.This()->GetPointerFromInternalField(0));
    if (t != NULL) t->volume(args[0]->NumberValue());
    return args.This();
}

Usage:

audio->PrototypeTemplate()->Set("Volume", v8::FunctionTemplate::New(&jsFunctionTemplate<Audio>));

Now if I could only figure out how to pass &Audio::volume to the template, I'll be in business.


Update on 7/24/2012

Refer to my answer for how I solved this.

Caleb Gray
  • 3,040
  • 2
  • 21
  • 32
  • 1
    Same general idea [here](http://stackoverflow.com/questions/9625526/check-at-compile-time-if-template-argument-is-void), it ends up being called like `wrap (someFunc, arg1, arg2, arg3)`. I hope that at least gives a start. – chris Jul 18 '12 at 19:04
  • What version of what compiler are you using? Specifically, can you use C++11? – ildjarn Jul 18 '12 at 19:08
  • gcc (Gentoo 4.5.3-r2 p1.1, pie-0.4.7) 4.5.3 -- How can I determine if I can use C++11? – Caleb Gray Jul 18 '12 at 19:14
  • 1
    @Caleb : You can use the subset of C++11 features listed [here](http://gcc.gnu.org/projects/cxx0x.html) for versions < 4.6. – ildjarn Jul 18 '12 at 19:17
  • What's the point of the template parameter `T`? You only seem to need to instantiate it with `Audio` as the template argument, so why bother parametrising it on that type? You want a function template that can call different functions, but always for `Audio`, right? – Jonathan Wakely Jul 24 '12 at 08:23
  • No, there are several classes like this: Audio, Material, Mesh, etc. See my answer below. – Caleb Gray Jul 24 '12 at 16:33

2 Answers2

6

Welcome to the magic of the lambda.

template<typename F> v8::Handle<v8::Value> jsAudio(const v8::Arguments &args, F&& f) {
    Audio *audio = static_cast<Audio*>(args.This()->GetPointerFromInternalField(0));
    if (audio != NULL) f(audio, args);
    return args.This();
}
int main() {
    jsAudio(..., [&](Audio* audio, const v8::Arguments &args) {
        audio->play(get(args[0], 0));
    });
}

For example.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • While this definitely put me on the right track, is it possible to make this even more generic? I'm using these templates as a callback: `audio->PrototypeTemplate()->Set("Play", v8::FunctionTemplate::New(&jsAudioPlay));` so they need to hold their `InvocationCallback` type... I'm hoping for the code to look something like this: `audio->PrototypeTemplate()->Set("Play", v8::FunctionTemplate::New(jsFunctionTemplate – Caleb Gray Jul 20 '12 at 19:26
  • @CalebGray, define "more generic". That function is pretty generic, it can be passed any callable object, such as a lambda, or `bind(&Audio::play, _1, bind(&get, bind(&Args::operator[], _2, 0), 0))` or `bind(&Audio::pause, _1)` or a `function` or a suitable functor etc. – Jonathan Wakely Jul 24 '12 at 08:30
  • The thing is, I need to pass the result as a pointer to a function: `v8::FunctionTemplate::New(&jsFunctionTemplate – Caleb Gray Jul 24 '12 at 16:36
-1

My Templates:

template <class T, class RT, RT(T::*f)()> v8::Handle<v8::Value> jsFunctionTemplate(const v8::Arguments &args) {
    T *t = static_cast<T*>(args.This()->GetPointerFromInternalField(0));
    if (t != NULL) (t->*f)();
    return args.This();
}
template <class T, class RT, class A0, RT(T::*f)(A0)> v8::Handle<v8::Value> jsFunctionTemplate(const v8::Arguments &args) {
    T *t = static_cast<T*>(args.This()->GetPointerFromInternalField(0));
    if (t != NULL) (t->*f)(jsConvert<A0>(args[0]));
    return args.This();
}
template <class T, class RT, class A0, class A1, RT(T::*f)(A0, A1)> v8::Handle<v8::Value> jsFunctionTemplate(const v8::Arguments &args) {
    T *t = static_cast<T*>(args.This()->GetPointerFromInternalField(0));
    if (t != NULL) (t->*f)(jsConvert<A0>(args[0]), jsConvert<A1>(args[1]));
    return args.This();
}

Usage:

audio->PrototypeTemplate()->Set("Play", v8::FunctionTemplate::New(&jsFunctionTemplate<Audio, Audio*, int, &Audio::play>));
audio->PrototypeTemplate()->Set("Pause", v8::FunctionTemplate::New(&jsFunctionTemplate<Audio, Audio*, &Audio::pause>));
audio->PrototypeTemplate()->Set("Loop", v8::FunctionTemplate::New(&jsFunctionTemplate<Audio, Audio*, int, &Audio::loop>));
audio->PrototypeTemplate()->Set("Volume", v8::FunctionTemplate::New(&jsFunctionTemplate<Audio, Audio*, float, &Audio::volume>));

Now I need to figure out the two final steps: variable number of arguments, and properly templating jsConvert to return the desired type <A0>.

Caleb Gray
  • 3,040
  • 2
  • 21
  • 32