【发布时间】:2017-10-12 07:16:08
【问题描述】:
好的,首先,我将提供我要提问的代码。
EX_Factory.h
#ifndef EX_FACTORY_H
#define EX_FACTORY_H
#include <string>
#include <map>
#include "Base.h"
struct EX_Factory{
template<class U, typename... Args>
static void registerC(const std::string &name){
registry<Args...>[name] = &create<U>;
}
template<typename... Args>
static Base * createObject(const std::string &key, Args... args){
auto it = registry<Args...>.find(key);
if(it == registry<Args...>.end()) return nullptr;
return it->second(args...);
}
private:
EX_Factory() = delete;
template<typename... Args>
static std::map<std::string, Base*(*)(Args...)> registry;
template<class U, typename... Args>
static Base* create(Args... args){
return new U(args...);
}
};
template<typename... Args>
std::map<std::string, Base*(*)(Args...)> EX_Factory::registry;
template<typename U, typename... Args>
struct MiddleMan{
MiddleMan(const std::string &name){
EX_Factory::registerC<U,Args...>(name);
}
};
#define REGISTER_MACRO(NAME, TYPE, ...)\ // Updated the macro here
static MiddleMan<TYPE, ##__VA_ARGS__> mm_##TYPE(#NAME);
#endif
上面的代码是我的工厂设计模式类的头文件。它允许此类的用户为从具有不同参数的 Base 类派生的对象注册构造函数。
好的,快速解释一下我为什么使用 __VA_ARGS__ vs ##__VA_ARGS__,原因是,总会有至少 1 个参数,即 registerC 模板函数中的模板类型 U,传递给宏。
我要做的是构造一个预处理器宏, REGISTER_MACRO ,在运行前注册派生类。如何从可变参数宏正确调用可变参数模板函数?
测试或 main.cpp
#include "EX_Factory_1.h"
#include <iostream>
using namespace std;
struct derived_1 : public Base{
derived_1(int i, int j, float f){
cout << "Derived 1:\t" << i * j + f << endl;
}
};
REGISTER_MACRO(name_1, derived_1, int,int,float);
struct derived_2 : public Base{
derived_2(int i, int j){
cout << "Derived 2:\t" << i + j << endl;
}
};
REGISTER_MACRO(name_2, derived_2, int,int);
int main(){ // Program segfaults before entering main
derived_1 * d_1 = static_cast<derived_1*>(EX_Factory::createObject<int, int, float>("name_1", 8, 8, 3.0));
if(d_1 == nullptr) cout << "Why is it null?" << endl;
else{
delete d_1;
}
return 0;
}
我在尝试编译上述代码时收到的错误: 请参阅下面的编辑
In file included from test.cpp:1:0:
EX_Factory.h:39:38: error: expected constructor, destructor, or type conversion before ‘(’ token
EX_Factory::registerC<__VA_ARGS__>(NAME);
^
test.cpp:11:1: note: in expansion of macro ‘REGISTER_MACRO’
REGISTER_MACRO("derived_1",derived_1,int,int,float)
^~~~~~~~~~~~~~
EX_Factory.h:39:38: error: expected constructor, destructor, or type conversion before ‘(’ token
EX_Factory::registerC<__VA_ARGS__>(NAME);
^
test.cpp:17:1: note: in expansion of macro ‘REGISTER_MACRO’
REGISTER_MACRO("derived_2",derived_2,int,int)
我使用的是 g++ 6.3 编译器,因此默认情况下,它在 Ubuntu 16.04 环境中使用 C++14 标准进行编译。
我找到了可能的解决方案,但不适合我的问题:
Is there a way to define variadic template macro
Using variadic macros or templates to implement a set of functions
可能的解决方案,但无法解释其解决方案:
How to use variadic template with variadic macro ? 我没有使用 QT,我使用的是完全支持的 C++11 编译器。
编辑
我现在知道为什么我的文件无法编译,但我不知道如何处理创建一个对象来为自己调用该方法。我添加了一个中间人类 MiddleMan,并在其构造函数中添加了对静态 registerC 类的调用,并修改了我的宏以创建对该类的静态引用。这允许我的程序编译,但它使用这种方法会出现段错误。您现在将看到上面提到的反射。
在我对this question 的回答中,我正在使用我的 main.cpp 测试这个类和宏。
【问题讨论】:
-
这与宏无关;问题是你不能在命名空间范围内编写函数调用。
-
@T.C.当然可以 -
int n = strlen(""); -
@NeilButterworth Fine,一个表达式语句。
-
@T.C.在命名空间范围内编写函数是什么意思?我正在调用一个静态函数,所以我对你的说法感到困惑。
-
@kennethCornett:在命名空间范围内,您只能编写声明。函数调用不是声明,即使函数是静态的。
标签: c++ macros c++14 variadic-templates variadic-macros