【问题标题】:C++ variadic templates function in variadic macro可变参数宏中的 C++ 可变参数模板函数
【发布时间】:2016-02-16 02:29:19
【问题描述】:

我目前正在开展一个需要简化现有系统的项目。 没有详细介绍,问题是我得到了一些函数指针(来自类型:void*),我需要从中创建一个函数(= 创建一个带有签名的函数)。所以我的方法是创建以下可变参数模板函数:

template <typename ReturnType, typename ... Params>
ReturnType(*GetFunction(void* func, Params ...)) (Params ...)
{
    return reinterpret_cast<ReturnType(*) (Params ...)> (func);
}

现在我需要一种方法来创建所需的功能:

#define DECLARE_PARAMS(...) __VA_ARGS__

#define Define_Function(returnType, fname, Params) returnType Gen_##fname (DECLARE_PARAMS Params)\
{\
    return  FUNCTION_DIRECTCALL(returnType, fname, (DECLARE_PARAMS Params));\
}

这就是问题所在。 (我认为)Params 没有按照他们应该扩展的方式扩展。但是不知道为什么?

我用硬编码值测试了 DEFINE_FUNCTION 宏中的 FUNCTION_DIRECTCALL(简单地将定义放入直接调用中),它工作正常,所以不应该有错误,但我愿意改进

#define FUNCTION_DIRECTCALL(returnType, functionName, ...) \
GetFunction<returnType>(functionName, DECLARE_PARAMS __VA_ARGS__) ( DECLARE_PARAMS __VA_ARGS__)

如果我尝试用宏定义一个函数

Define_Function(void, ThatFunction, (int a_, int b_)); // void ThatFunction(int a, int b);

我收到以下错误:“严重性代码描述项目文件行抑制状态错误(活动)不允许不完整类型 [...]\main.cpp 34”

所以我的问题是,我做错了什么?问题真的与 DEFINE_FUNCTION 宏中的参数有关还是我错过了什么?

我曾使用宏,但我不会称自己为该领域的专家。但我的理解是 (DECLARE_PARAMS Params) 应该将参数扩展为:

int a_, int b_

扫描后我会看到以下代码:

void Gen_ThatFunction(int a_, int b_)
{
    return GetFunction<void>(ThatFunction, a_, b_) (a_, b_);
}

测试 Directcall 宏: 我用下面的代码测试了 directcall 宏的功能

因此我更改了Define_Function 宏:

#define Define_Function(returnType, fname, Params) returnType Gen_##fname (DECLARE_PARAMS Params)   \
{\
    int a = 2, b = 3;\
    return  FUNCTION_DIRECTCALL(void, ThatFunction, (a, b) );\
}

ThatFunction的定义:

void ThatFunction(int a, int b)
{
    std::cout <<  a << " * " << b << " = " << b * a << std::endl;
}

输出:“2 * 3 = 6”

在 VC++ 2015 中编译的所有代码

【问题讨论】:

  • 你确定不应该是DECLARE_PARAMS(Params)
  • 我根本看不到DECLARE_PARAMS 的意义。只需省略号并使用__VA_ARGS__。无需通过另一个宏转发。
  • @chris 在这种情况下转发没有意义。但是内部使用是必须的(以后)。
  • 好吧,无论如何,您不能将逗号分隔的列表作为一个参数传递。 Params 作为宏参数不会神奇地容纳多个参数。这就是省略号的用途。
  • @Claudiu 是的,我确信我的做法是正确的。没找到解释稍后贴(找到后)

标签: c++ variadic-templates variadic-macros


【解决方案1】:

我知道如何做你所要求的唯一方法真的很笨重。

#define DEFINE_FUNCTION(RET, NAME, TYPES, NAMES, BOTH) RET Gen_##NAME BOTH { return reinterpret_cast<RET(*)TYPES>(NAME) NAMES;  }

你像这样使用它:

DEFINE_FUNCTION(void, ThatFunction, (int, int), (a_, b_), (int a_, int b_))

void*(或函数)的返回类型和名称是前两个参数。接下来是用括号括起来的参数类型列表,以及括起来的参数名称,最后是括起来的类型和名称。就像我说的,笨重。

这将生成函数:

void Gen_ThatFunction (int a_, int b_) { return reinterpret_cast<void(*)(int, int)>(ThatFunction) (a_, b_); }

然后您可以根据需要调用该函数:

Gen_ThatFunction(2, 3); //prints "2 * 3 = 6"

当然,请记住这是 Microsoft 特有的。这里,括号中的逗号分隔项是单个宏参数。在任何其他编译器上,这都行不通(据我所知)。

【讨论】:

  • 这是我对这个问题的第一个解决方案。但是客户想要一个更“直观”的解决方案。如果您查看 DEFINE_FUNCTION,您会看到该宏看起来与函数声明完全一样。这是我想要在不开发整个反射系统的情况下实现的目标。
  • @MainCPP 函数是否有重载?如果只有一个Gen_ThatFunction,您可以引用可变参数函数模板。否则,我认为您只能使用可变参数函数而没有可见的设置参数列表。
  • 是的,它们是重载。目前我已经通过使用固定数量的参数宏(DECLARE_FUNCTION_ONE_PARAM)解决了这个问题,参数将我用逗号分隔,所以问题很容易解决。我会接受你的回答,因为它是所描述问题的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-01
  • 2017-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多