有沒有辦法在不手動創建字串和類之間的映射的情況下實作以下代碼的功能?
template<class base, typename T>
base* f(const std::string &type, T &c) {
if(type == "ClassA") return new ClassA(c);
else if(type == "ClassB") return new ClassB(c);
// many more else if...
return nullptr;
}
所有類看起來像這樣:
class ClassA: public BaseClass {
public:
std::string label="ClassA";
...
};
我們可以將其用作:
BaseClass *b = f<BaseClass>("ClassA", DifferentObject);
每個新類都會產生if else一行新代碼。有什么方法可以自動執行此操作,以便f在添加新支持的類時功能“更新”自身?該解決方案必須適用于 C 11。
uj5u.com熱心網友回復:
一個可能的宏:
#include <memory>
#include <string>
class BaseClass {};
class ClassA : public BaseClass {
public:
std::string label = "ClassA";
explicit ClassA(int /*unused*/) {}
};
class ClassB : public BaseClass {
public:
std::string label = "ClassB";
explicit ClassB(int /*unused*/) {}
};
template<class base, typename T>
auto f(const std::string &type, T c) -> std::unique_ptr<base> {
#define CASE(NAME) \
if (type == "NAME") { \
return std::unique_ptr<base>(new NAME(c)); \
}
CASE(ClassA)
CASE(ClassB)
//...
#undef CASE
return nullptr; // Statement at the end needed for last else!
}
auto main() -> int {
auto b = f<BaseClass>("ClassA", 0);
}
也使用,unique_ptr因為記憶體管理原始指標是邪惡的。
uj5u.com熱心網友回復:
在這種情況下,如果類名等于字串,您可以使用以下宏簡化代碼:
#define STRING_TO_CLASS (className) if(type == "className") return new className(c);
template<class base, typename T>
base* f(const std::string &type, T &c) {
STRING_TO_CLASS(ClassA)
STRING_TO_CLASS(ClassB)
return nullptr;
}
我個人討厭宏,但它只會打擾我。但是,在編譯時,將在決議宏后生成以下代碼。
template<class base, typename T>
base* f(const std::string &type, T &c) {
if(type == "ClassA") return new ClassA(c);
if(type == "ClassB") return new ClassB(c);
return nullptr;
}
如您所見,最后只else洗掉了關鍵字。此外,如果添加了新類,您需要修改代碼。
uj5u.com熱心網友回復:
您可以像這樣使用注冊表模式:
#include <map>
#include <functional>
#include <string>
template< typename T, typename X >
using Factory = std::function< T* ( X& ) >;
template< typename Base, typename X >
struct Registry {
using Map = std::map<std::string,Factory<Base,X> >;
static Map registry;
template< typename T >
struct Register {
Register( const std::string& name ) {
registry[ name ] = []( X& x ) -> T* { return new T(x); };
}
};
};
template< typename Base, typename X >
Base* factory(const std::string &type, X &c ) {
auto it = Registry<Base,X>::registry.find( type );
if ( it!=Registry<Base,X>::registry.end() ) {
return (it->second)(c);
}
return nullptr;
}
struct X {};
struct A {
A( X& x ) {};
virtual ~A() {}
};
struct B : public A {
B( X& x ) : A(x) {};
};
struct C : public A {
C( X& x ) : A(x) {};
};
struct D : public B {
D( X& x ) : B(x) {};
};
// Register class
template<> Registry<A,X>::Map Registry<A,X>::registry{};
Registry<A,X>::Register<B> regB( "B" );
Registry<A,X>::Register<C> regC( "C" );
Registry<A,X>::Register<D> regD( "D" );
#include <iostream>
int main() {
X x;
A* ptr = factory<A,X>( "B", x );
B* bptr = dynamic_cast<B*>( ptr );
if ( bptr!= nullptr ) {
std::cout << "Success!" << std::endl;
return 0;
}
std::cout << "Failed!" << std::endl;
return 1;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/373614.html
上一篇:Mysqljson二進制編碼
下一篇:使用向量回傳型別遍歷二叉樹
