c++ - 如何转发未命名的函数参数
问题描述
所以,我正在尝试为我的虚拟类函数创建一个模拟宏。
这是具有一个模拟函数的模拟类的示例。(这按预期工作)
class MockEnvironment : public IEnvironment {
public:
using runType = int(std::string program,
std::vector<std::string> arguments);
MockedFunction<runType> runMock = MockedFunction<runType>("run");
int run(std::string program, std::vector<std::string> arguments) override {
return runMock(program, arguments);
}
// MOCK_METHOD(int, run, (std::string, std::vector<std::string>)); // this is the goal
};
MockedFunction
是一个带有 operator() 的类,它应该在函数被调用时被调用。
我的目标是将函数包装在一个宏中,以便能够模拟任何函数。您可能看到的问题是,在概括时,我需要处理一个带有未命名参数的函数。
#define MOCK_METHOD(ret, name, args) \
MockedFunction<ret(args)> mocked_##name = \
MockedFunction<ret(args)>(#name); \
ret name##Mock(args) { /* how to solve? */ }
// This would expand to something like
MockedFunction<...> runMock = MockedFunction<...>("run"); // More detailed in above example
int run(std::string, std::vector<std::string>) override {
return runMock(/*how to forward the arguments when they do not have names?*/)
}
我曾想过使用某种可变参数模板,但我还没有找到任何方法让它工作。我也尝试阅读谷歌的模拟实现,但我发现很难看到他们是如何解决它的。
所以我的问题很简单。如何将参数的内容移动run
到要调用的函数中?
我最多可以使用 c++17。我确实意识到,如果您在宏中指定需要多少个参数会更容易,但如果可以解决更一般的示例,那将是最佳选择。
编辑:如果我事先知道参数的数量,这是我想出的最好的方法。
#define INTERNAL_MOCK_METHOD_COMMON(ret, name, args) \
using name##T = ret(args); \
unittest::MockedFunction<ret(args)> mock_##name = \
unittest::MockedFunction<ret(args)>(#name);
#define MOCK_METHOD(ret, name) \
INTERNAL_MOCK_METHOD_COMMON(ret, name, ()) \
ret name() { \
return mock_##name(); \
}
#define MOCK_METHOD1(ret, name, args) \
INTERNAL_MOCK_METHOD_COMMON(ret, name, args) \
ret name(typename unittest::MockedFunction<name##T>::ArgT<0>::type a) { \
return mock_##name(a); \
}
#define MOCK_METHOD2(ret, name, args) \
INTERNAL_MOCK_METHOD_COMMON(ret, name, args) \
ret name(typename unittest::MockedFunction<name##T>::ArgT<0>::type a, \
typename unittest::MockedFunction<name##T>::ArgT<1>::type b) { \
return mock_##name(a, b); \
}
// ...
template <typename T>
class MockedFunction {};
template <typename ReturnT, typename... ArgsT>
class MockedFunction<ReturnT(ArgsT...)> {
public:
// Return argument type at the specified index
template <int i>
struct ArgT {
using type = typename std::tuple_element_t<i, std::tuple<ArgsT...>>;
};
那么就可以这样使用
class IObject {
public:
virtual int update() = 0;
virtual void setValue(int) = 0;
};
class MockObject : public IObject {
public:
MOCK_METHOD(int, update);
MOCK_METHOD1(void, setValue, (int));
};
明确一点:不必用数字指定参数的数量会很好。
解决方案
您不能使用未命名的参数。你可以考虑给它们命名,可能是这样的:
#define MOCK_METHOD(ret, name, args, names) \
MockedFunction<ret(args)> mocked_##name = \
MockedFunction<ret(args)>(#name); \
ret name##Mock(args) { return runMock names; }
MOCK_METHOD(int, run, (std::string s, std::vector<std::string> v), (s, v));
推荐阅读
- spring - ECS服务与spring微服务和AWS cloudmap的通信
- ios - 使用 SwiftUI 从 SessionDownloadDelegate 显示进度
- sql - 计算组中最大数量的变量
- c - Assignment_SDD_Proj.exe 中 0x0F64F6E0 (ucrtbased.dll) 处的未处理异常:0xC0000005:访问冲突读取位置 0x00000000
- c - 试图找出这个例子的位掩码
- date - 在 Pharo 8 中转换指定模式的日期字符串
- wordpress - 当点击wordpress中的按钮时,可以在图像标题中添加1个按钮以获取有关该图像的表单查询?
- django - 根据Django中关联模型的属性过滤父模型实例
- python - Pandas 上的数据框聚合问题
- reactjs - npm postinstall 仅在未安装任何内容时运行