gpt4 book ai didi

c++ - 具有继承历史的 CRTP 插件自动注册(尝试但失败了 SFINAE)

转载 作者:行者123 更新时间:2023-11-30 05:42:48 31 4
gpt4 key购买 nike

我已经使用 CRTP 为插件系统构建了一个自动注册框架,效果很好。当我想拥有它的继承历史时,问题就来了。我最初的计划是在类自动注册时累积父 ID 的 vector 。我的尝试在下面的代码中,因为它相当长,所以我把它放在问题的末尾。

InterfaceFactory 和 AutoRegister 类通过 CRTP 工作正常(即使 AutoRegister 功能被多次继承)。系统能够根据提供的 id 创建正确的类型,并且所有注册功能都是由编译器在编译时构建的。

我想添加继承历史是在他们注册时添加继承,看起来很简单。我计划在注册期间使用静态“InterfaceType s_type”来获取 INTERFACE 类的信息并添加到当前。问题是原始接口(interface)调用“BaseInterface”(和类似的接口(interface))没有 s_type。接下来的想法是使用 SFINAE 忽略层次结构中的那些类(因为它无论如何都没有 id)。这导致了 AutoRegister 中的 BaseId 结构,它试图关闭 s_type。然而,这似乎不起作用,因为从未使用过特化。我假设 Base::BaseId 是使用非专用的创建的,因为没有 BaseInterface::s_type 并且当 Derived 被注册时(因为它是从 Base 派生的)编译器正在获取 Base::BaseId 并且甚至没有尝试特化。所以我的问题是,这个假设是否正确?如果可以,有人可以稍微解释一下吗,因为我对细节不太清楚,还有其他方法可以做到这一点吗?

#include <vector>
#include <functional>

template <typename T> struct TypeName
{
static std::string get()
{
std::string fullName=typeid(T).name();

size_t beginPos=0;
size_t classPos=fullName.find("class");
size_t nameSpacePos=fullName.find_last_of("::");

if(classPos != std::string::npos)
beginPos=classPos+6;
if(nameSpacePos != std::string::npos)
{
if(nameSpacePos+1 > beginPos)
beginPos=nameSpacePos+1;
}
return fullName.substr(beginPos);
}
};

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

struct InterfaceType
{
InterfaceType():id(-1){}

unsigned int id;
std::vector<unsigned int> idInheritance;
std::string name;
};

template<typename CLASS, typename INTERFACE>
class AutoRegister:public INTERFACE
{
public:
AutoRegister():INTERFACE() { &s_type; }

static BaseInterface *create(unsigned int type) { CLASS *newClass=new CLASS(); return newClass; }

template<typename T, typename=int>
struct BaseId
{
static std::vector<unsigned int> get() { return std::vector<unsigned int>(); }
};

template<typename T>
struct BaseId<T, decltype((void)T::s_type, 0)>
{
static std::vector<unsigned int> get()
{
std::vector<unsigned int> ids;
ids.push_back(T::s_type.id); ids.insert(ids.end(), T::s_type.idInheritance.begin(), T::s_type.idInheritance.end());
return ids;
}
};

static std::vector<unsigned int> getBaseIds() { return BaseId<INTERFACE>::get(); }

private:
static InterfaceType s_type;

};

class InterfaceFactory
{
public:
typedef BaseInterface *(*FactoryFunc)(unsigned int type);
class BaseInterfaceNode
{
public:
BaseInterfaceNode(unsigned int type, std::string typeName, FactoryFunc factoryFunction):
m_type(type), m_typeName(typeName), m_factoryFunction(factoryFunction)
{};

size_t type() { return m_type; }
std::string typeName() { return m_typeName; }
BaseInterface *factoryFunction() { return m_factoryFunction(m_type); }

private:
unsigned int m_type;
std::string m_typeName;
FactoryFunc m_factoryFunction;
};
typedef std::vector<BaseInterfaceNode> BaseInterfaceNodes;

public:
InterfaceFactory() {}
~InterfaceFactory() {}

public:
static BaseInterface *createType(unsigned int type);
static InterfaceType registerType(std::string typeName, std::vector<unsigned int> ids, FactoryFunc factoryFunc);

struct BaseInterfaceNodeHolder
{
BaseInterfaceNodeHolder():s_interfaceTypeIndex(0) {}

BaseInterfaceNodes s_baseInterfaceNodes;
unsigned int s_interfaceTypeIndex;
};

private:
};

template<typename CLASS, typename INTERFACE> InterfaceType AutoRegister<CLASS, INTERFACE>::s_type=\
InterfaceFactory::registerType(TypeName<CLASS>::get(), AutoRegister<CLASS, INTERFACE>::getBaseIds(), &AutoRegister<CLASS, INTERFACE>::create);

InterfaceFactory::BaseInterfaceNodeHolder *s_nodes=nullptr;

InterfaceType InterfaceFactory::registerType(std::string typeName, std::vector<unsigned int> ids, FactoryFunc factoryFunc)
{
if(s_nodes == nullptr)
s_nodes=new BaseInterfaceNodeHolder();

InterfaceType sampleType;

sampleType.id=s_nodes->s_interfaceTypeIndex;
sampleType.idInheritance=ids;
sampleType.name=typeName;

s_nodes->s_baseInterfaceNodes.push_back(BaseInterfaceNode(s_nodes->s_interfaceTypeIndex, typeName, factoryFunc));
s_nodes->s_interfaceTypeIndex++;
return sampleType;
}


//////////////////////////////////////////////////////////////////////

class Base:public AutoRegister<Base, BaseInterface>
{
};

class Derived:public AutoRegister<Derived, Base>
{
};





int main(int argc, const char* argv[])
{
Base base;
Derived derived;

return 0;
}

谢谢,

最佳答案

好吧,我发现了我自己的错误,似乎 SFINAE 的风格要求我检查的成员变量是公开的,一旦我改变了

private:
static InterfaceType s_type;

public:
static InterfaceType s_type;

它解决了问题,至少对于 Clang(可能还有 gcc)来说是这样。但是 VS2013 没有工作。阅读了一下之后,当涉及到一些高级模板时,VS2013 中似乎可能存在一些错误。大多数似乎已修复但尚未发布。最后我不得不使用 Johannes Schaub - litb ( How to detect whether there is a specific member variable in class? ) 提供的版本。我包含了一个 has_s_type

template <typename T>
struct has_s_type
{
struct Fallback { InterfaceType s_type; };
struct Derived: T, Fallback {};

template<typename C, C> struct ChT;
template<typename C> static char(&f(ChT<InterfaceType Fallback::*, &C::s_type>*))[1];
template<typename C> static char(&f(...))[2];

static bool const value=sizeof(f<Derived>(0)) == 2;
};

并将AutoRegister修改为

template<typename CLASS, typename INTERFACE>
class AutoRegister:public INTERFACE
{
public:
AutoRegister():INTERFACE() { &s_type; }

static BaseInterface *create(unsigned int type) { CLASS *newClass=new CLASS(); return newClass; }

template<typename T, bool=false>
struct BaseId
{
static std::vector<unsigned int> get() { return std::vector<unsigned int>(); }
};

template<typename T>
struct BaseId<T, true>
{
static std::vector<unsigned int> get()
{
std::vector<unsigned int> ids;
ids.push_back(INTERFACE::s_type.id); ids.insert(ids.end(), INTERFACE::s_type.idInheritance.begin(), INTERFACE::s_type.idInheritance.end());
return ids;
}
};

static std::vector<unsigned int> getBaseIds() { return BaseId<INTERFACE, has_s_type<INTERFACE>::value>::get(); }

public:
static const InterfaceType s_type;

};

这是一些live code

关于c++ - 具有继承历史的 CRTP 插件自动注册(尝试但失败了 SFINAE),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30518410/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com