如何从可变参数宏正确调用可变参数模板函数?

How to correctly call a variadic template function from a variadic macro?

好的,首先,我将提供我提出问题的代码。

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

上面的代码是我的工厂设计模式 class 的头文件。它允许此 class 的用户为从 Base class 派生的具有不同参数的对象注册构造函数。

好吧,快速解释一下为什么我使用 __VA_ARGS__ vs ##__VA_ARGS__,原因是,总会有至少 1 个参数,registerC 中的模板类型 U模板函数,传入宏。

我想做的是构造一个预处理器宏, REGISTER_MACRO ,在运行前注册派生的 classes。如何从 可变参数宏 中正确调用 可变参数模板函数

测试或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 编译器,因此默认情况下,它使用 C++14 标准编译 Ubuntu 16.04环境。

我找到的潜在解决方案,但不适合我的问题:

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 编译器。

编辑

我现在知道为什么我的文件无法编译,但我不知道如何创建一个对象来为自己调用该方法。我添加了一个中间人 class,MiddleMan,并在其构造函数中添加了对静态 registerC class 的调用,并修改了我的宏以创建对此 class 的静态引用。这允许我的程序编译,但使用此方法会出现段错误。您现在将看到上面提到的反射。

我正在测试这个 class 并在我对 this question 的回答中用我的 main.cpp 进行宏输出。

好吧,在@rici 的帮助下,进行了一些研究,并事先提到了@T.C 的原因。我开发了一个修改后的设计,它使用 Registrator 对象将 BaseDerived Objects 注册到我的工厂设计中.

为了绕过我遇到的段错误,我决定实施 Functors 来存储我的 template create 函数。我设计了一个基本函子 F 和一个模板派生函子 DF.

我创建了一个 getMap() 方法,该方法将 reference 返回给存储 std 的静态地图对象: :string and base functor pointer,F*, pairs in it.

我的解决方案代码如下!

FunctorFactory.h

#ifndef FUNCTOR_FACTORY_H
#define FUNCTOR_FACTORY_H

#include <map>
#include <string>

#include "Base.h"

struct FunctorFactory{
    private:
        class F{ // Base Functor
            public:
                virtual ~F(){}
        };
        template<typename R, typename... A>
        struct DF : public F{ // Templated Derived Functors
            DF(R (*f)(A...)); // Regular Constructor
            DF(const DF<R,A...>& df); // Copy Constructor
            virtual ~DF(); // Virtual Destructor
            virtual R operator()(A... args); // Overloaded () to allow function like use.
            virtual DF<R,A...>& operator=(const DF<R,A...>& df); // Overloaded = to allow assignment

            private:
                R (*_f)(A...); // The actual function being called
        };
        static std::map<std::string,F*>& getMap(); // Map pairing string keys to their Functors(stored as Base Functors)
        template<typename U, typename... A> // Templated create function which will create the derived objects being requested!
        static Base * create(A... args);
    public:
        template<typename U, typename... A> // Registrator class which registers objects
        struct Registrator{
            Registrator(const std::string &key);
        };
        template<typename... A> // createObject static method which creates the requested object
        static Base * createObject(const std::string &skey, A... args);
};

// Implementation of the derived functor's methods
template<typename R, typename... A> // Basic Constructor.
FunctorFactory::DF<R,A...>::DF(R (*f)(A...)){_f = f;}
template<typename R, typename... A> // Copy Constructor.
FunctorFactory::DF<R,A...>::DF(const FunctorFactory::DF<R,A...>& df){_f = df._f;}
template<typename R, typename... A> // Destructor
FunctorFactory::DF<R,A...>::~DF(){}
template<typename R, typename... A> // Overloaded () operator
R FunctorFactory::DF<R,A...>::operator()(A... args){return _f(args...);}
template<typename R, typename... A> // Overloaded = operator
FunctorFactory::DF<R,A...>& FunctorFactory::DF<R,A...>::operator=(const FunctorFactory::DF<R,A...>& df){_f = df._f;}

std::map<std::string,FunctorFactory::F*>& FunctorFactory::getMap(){ // Get map class
    static std::map<std::string,FunctorFactory::F*> m_map; // The actual map storing the functors.
    return m_map;
}

template<typename U, typename... A>
Base * FunctorFactory::create(A... args){
    return new U(args...);
}

template<typename U, typename... A>
FunctorFactory::Registrator<U,A...>::Registrator(const std::string &key){
    DF<Base*,A...> * df = new DF<Base*,A...>(FunctorFactory::create<U,A...>);
    getMap()[key] = df;
}
template<typename... A>
Base * FunctorFactory::createObject(const std::string &skey, A... args){
    auto it = getMap().find(skey);
    if(it == getMap().end()) return nullptr;
    DF<Base*,A...> * df = static_cast<DF<Base*,A...>*>(it->second);
    return (*df)(args...);
}

    #ifndef FF_MACRO
        #define FF_MACRO(NAME,TYPE,...)\
            namespace { \
                ::FunctorFactory::Registrator<TYPE,##__VA_ARGS__> registrator_##NAME(#NAME); \
            }
    #endif

#endif // FUNCTOR_FACTORY_H

Base.h

#ifndef BASE_H
#define BASE_H

class Base{
    public:
        virtual ~Base(){}
};

#endif

main.cpp

#include "FunctorFactory.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;
    }
};
FF_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;
    }
};
FF_MACRO(name_2, derived_2, int,int);

int main(){
    derived_1 * d_1 = static_cast<derived_1*>(FunctorFactory::createObject<int, int, float>("name_1", 8, 8, 3.0));
    if(d_1 == nullptr) cout << "The function being requested must either have different parameters or a different key." << endl;
    else{
        delete d_1;
    }
    return 0;
}

输出

Derived 1:  67

我希望这对遇到与此类似问题的任何人有所帮助。 如果需要,也可以随意使用此工厂模型。它能够将重载构造函数的多个不同映射存储到相同的对象类型以及多个不同的派生对象。