其他分享
首页 > 其他分享> > C variadic模板参数方法传递给没有可变参数的方法

C variadic模板参数方法传递给没有可变参数的方法

作者:互联网

我有以下问题,我真的无法编译所有研究的问题和文章:

在C中,是否可以使用具有可变参数模板参数的方法来指定参数类型(作为某种类型的输入,输出,输入/输出参数的元描述类型,通过值,地址等传递) .),循环遍历这些可变参数以实例化指定类型的变量,并将这些变量传递给模板参数中指针指定的函数,但这些函数没有可变参数?

编辑1

我在这里尝试细节,作为伪代码:

template <decltype(*Type::*Method), typename... Parameters>
static bool ExecuteMethod(JSContext *cx, unsigned argc, JS::Value *vp)
{
    JS::CallArgs args = CallArgsFromVp(argc, vp);

    loop through Parameters
    {
        Parameters[i]::Type p[i] <-- args[i];
    }

    ReturnType r = Method(p[0], p[1], p[2] .. p[n]); // the method does not have variadic parameters
...
}

方法可能是这样的:

int(*GetColor) ( int16 *color);
int(*GetFile) ( FilePath &file );
int(*WriteDocument) ( const FilePath &file, const char *fileFormatName, bool askForParms);

等等

这源于包装需求.
C中缺少挑战,如.net中的反射.
通过以某种方式循环遍历可变参数,可以实例化异构对象的数组?大概.
但是如何将它们传递给没有可变参数的方法呢?我认为不可能在不使用显式包装器的情况下将该对象数组分配给上述三个函数,不是吗?

编辑2

我有很多反馈,但很明显我不够具体.
我没有详细说明,因为过去因为过于具体而抱怨我.实际上,我没有简单的实现,我是一个普通人,不是懒惰,但我试图让后一个开发更快.

以下是问题的根源:我需要包装Adobe Illustrator API,它会公开数百个(如果不是数千个)指向以结构形式分组的函数(称为套件)的指针.

我尝试使用SpiderMonkey创建一个javascript引擎.

我使用Visual Studio 2015编译器.

我的方法如下:

我有几个类来包装API,以便为所有套件添加SpiderMonkey的引擎对象.每个SpiderMonkey类都可以调用为jsData,包装数据类型的Adobe SDK或套件jsSuite.

到目前为止,我使用了模板,因为SpiderMonkey强制我将每个函数添加到具有特定签名的自定义对象,如下所示:

bool jsAIDocumentSuite::WriteDocument(JSContext *cx, unsigned argc, JS::Value *vp)
{
...
}

并将其添加到自定义对象将完成如下:

const JSFunctionSpec jsAIDocumentSuite::fFunctions[] = {
...
    JS_FN("WriteDocument", jsAIDocumentSuite::WriteDocument, 3, 0),
...
}

JS_FN是一个SpiderMonkeyMacro.

实际上,到目前为止,这只是Adobe SDK的不到10%.

最多的是带有一个参数的getter和setter,通过值或地址或指针传递,所以我用一个泛型函数替换它们,如下所示:

    template <typename jsType, typename jsReturnType, typename ReturnPrivateType = jsReturnType::PrivateType, typename jsParamType, typename ParamPrivateType = jsParamType::PrivateType, ReturnPrivateType(*Type::*Method)(ParamPrivateType&)>
    static bool GetByRefMethod(JSContext *cx, unsigned argc, JS::Value *vp)
    {
        JS::CallArgs args = CallArgsFromVp(argc, vp);

        try
        {
            ReturnPrivateType result;

            ParamPrivateType ppt;

            if (jsType::Suite() && (jsType::Suite()->*Method))
                result = (jsType::Suite()->*Method)(ppt);
            else
                return false; // TODO throw a meaningful error

            if ((jsReturnType::IsNoError(result)) && (argc > 0) && (args[0].isObject()))
            {
                JSObject *obj = &args[0].toObject();

                JSObject *value = NULL;
                if (!jsParamType::FromAIObject<jsParamType>(cx, &ppt, value))
                    return false;

                if (!value)
                    return false;

                jsProperty::SetProperty(cx, &obj, "value", value, true);
            }

            JSObject *obj = JS_NewObject(cx, &jsDataClass<jsReturnType>::fClass);

            JS_SetPrivate(obj, new ReturnPrivateType(result));

            args.rval().setObject(*obj);
        }
        EXCEPTION_CATCH_CONVERT();

        return true;
    }

有点复杂,不是吗?

以上相关内容是:

> args变量保存由其引擎传入的SpiderMonkey参数
>这里只传递一个参数,ppt
>返回类型是一个值,因此很容易处理

我使用宏来在其变体中注入方法(也有几种简短的形式,这里不那么有趣):

JS_FN(#GET_METHOD, (js##TYPE::GetByRefMethod<js##TYPE, RETURN_JS_TYPE, RETURN_PRIVATE_TYPE, PARAM_JS_TYPE, PARAM_PRIVATE_TYPE, &TYPE::GET_METHOD>), 1, 0)

我希望能够处理变量参数,根据更具哲学性但有趣的统计数据.这个想法可能与C相反,而不是预期的.

我怎么期待它:

我希望添加可变参数元信息,如:

模板
        static bool方法(JSContext * cx,unsigned argc,JS :: Value * vp)
        {
            JS :: CallArgs args = CallArgsFromVp(argc,vp);

        try
        {
            ReturnPrivateType result;

            *1st challenge: Loop through the variadic list of meta-parameters and create their corresponding object instances here and initialize the IN ones with values from the *args* collection passed by the SpiderMonkey engine*

            if (jsType::Suite() && (jsType::Suite()->*Method))
                result = (jsType::Suite()->*Method)(*2nd challenge: pass arguments here: probably by using a variadic macro?*);
            else
                return false; // TODO throw a meaningful error

            if ((jsReturnType::IsNoError(result)) && (argc > 0) && (args[0].isObject()))
            {
                JSObject *obj = &args[0].toObject();

                JSObject *value = NULL;
                if (!jsParamType::FromAIObject<jsParamType>(cx, &ppt, value))
                    return false;

                if (!value)
                    return false;

                jsProperty::SetProperty(cx, &obj, "value", value, true);
            }

            JSObject *obj = JS_NewObject(cx, &jsDataClass<jsReturnType>::fClass);

            JS_SetPrivate(obj, new ReturnPrivateType(result));

            args.rval().setObject(*obj);
        }
        EXCEPTION_CATCH_CONVERT();

        return true;
    }

正如你所看到的,它不是C预期的,它有点颠倒,试图避免编写模板来扣除参数,在这里,我首先知道参数并尝试编写代码以通过了解它们来生成正确的参数首先是元信息,我有一组清晰的类型,我保证会编写正确的代码来生成正确的包装器.我不需要对参数数据进行太多验证,因为事情通常在过程中没有庞大的业务逻辑.

编辑3

关于参数元信息,我可以编写一些带静态的类型来指定参数的数据类型,无论是返回类型,是IN,OUT还是IN / OUT参数,jsType等. .
它们将是上面模板参数函数的可变列表.

解决方法:

[续第1部分:https://stackoverflow.com/a/35109026/5386374]

但是,有一个问题.我们必须改变编写代码的方式来容纳ExecuteMethod(),这可能并不总是可行的.有没有解决方法,以便它的功能与您之前指定的ExecuteMethod()完全相同,并且不需要将它修改的变量作为宏参数?答案是……是的!

// Variadic function-like macro to automatically create, use, and destroy functor.
// Uncomment whichever one is appropriate for the compiler used.
//  (The difference being that Visual C++ automatically removes the trailing comma if the
//   macro has zero variadic arguments, while GCC needs a hint in the form of "##" to tell
//   it to do so.)
// Instead of a do...while structure, we can just use a temporary Executor directly.
// MSVC:
// #define ExecuteMethod(M, ...) Executor<decltype(&M), decltype(&M)>{}(M, __VA_ARGS__)
// GCC:
#define ExecuteMethod(M, ...) Executor<decltype(&M), decltype(&M)>{}(M, ##__VA_ARGS__)

// For your example function WriteDocument(), defined as
//   int WriteDocument(const FilePath &file, const char *fileFormatName, bool askForParms);

bool c = ExecuteMethod(WriteDocument, file, fileFormatName, askForParams);

这一切都很好,但我们可以做一个更改,以简化事情而不影响性能.目前,这个仿函数只能接受函数指针(也许是lambdas,我不熟悉它们的语法),而不是其他类型的函数对象.如果这是预期的,这意味着我们可以重写它以取消第一个模板参数(整个签名),因为第二个和第三个参数本身就是签名的组成部分.

// Default functor.
template<typename... Ts>
struct Executor { };

// General case.
template<typename ReturnType, typename... Params>
struct Executor<ReturnType (*)(Params...)> {
    private:
        // Instead of explicitly taking M as a parameter, create it from
        //  the other parameters.
        using M = ReturnType (*)(Params...);
    public:
        // Parameter match:
        bool operator()(M method, Params... params) {
            ReturnType r = method(params...);
            // ...
        }

        // Parameter mismatch:
        template<typename... Invalid_Params>
        bool operator()(M method, Invalid_Params... ts) {
            // Handle parameter type mismatch here.
        }
};

// Special case to catch void return type.
template<typename... Params>
struct Executor<void (*)(Params...)> {
    private:
        // Instead of explicitly taking M as a parameter, create it from
        //  the other parameters.
        using M = void (*)(Params...);
    public:
        // Parameter match:
        bool operator()(M method, Params... params) {
            method(params...);
            // ...
        }

        // Parameter mismatch:
        template<typename... Invalid_Params>
        bool operator()(M method, Invalid_Params... ts) {
            // Handle parameter type mismatch here.
        }
};

// Variadic function-like macro to automatically create, use, and destroy functor.
// Uncomment whichever one is appropriate for the compiler used.
//  (The difference being that Visual C++ automatically removes the trailing comma if the
//   macro has zero variadic arguments, while GCC needs a hint in the form of "##" to tell
//   it to do so.)
// Instead of a do...while structure, we can just use a temporary Executor directly.
// MSVC:
// #define ExecuteMethod(M, ...) Executor<decltype(&M)>{}(M, __VA_ARGS__)
// GCC:
#define ExecuteMethod(M, ...) Executor<decltype(&M)>{}(M, ##__VA_ARGS__)


// Note: If your compiler doesn't support C++11 "using" type aliases, replace them
//       with the following:
//           typedef ReturnType (*M)(Params...);

这会产生更干净的代码,但如上所述,它限制了仿函数只接受函数指针.

当像这样使用时,仿函数期望参数完全匹配.它可以正确处理引用和cv-ness,但可能与rvalues有问题,我不确定.见here.

至于如何在你的JSContext中使用它…我真的不确定.我还没有了解过上下文,所以其他人会更有帮助.我建议检查一下这里的其他答案是否会在你的情况下更加有用,一切都是诚实的.

注意:我不确定如果函数参数是functor,lambda,std :: function或任何类型的函数,修改函数是多么容易.

注2:和以前一样,我不确定做这样的事情是否会对性能产生任何负面影响.可能有一种更有效的方式,但我不知道它会是什么.

标签:variadic,c,function,templates,loops
来源: https://codeday.me/bug/20190829/1760487.html