【发布时间】:2016-06-01 08:32:20
【问题描述】:
我最近一直在玩std::map,并想出了一个宏伟的 :D 设计来创建优先级地图 - 一个包含根据优先级分组的各种模式的地图。
我有以下类结构:
Mode
|
|----ModeSleep
|----ModeFactorial
Mode 在哪里:
class Mode
{
std::string name; ///< Mode's name
int priority; ///< Mode's priority used for storing the Mode in a specific priority group in the priority map. Default: 0
public:
Mode();
///
/// \brief Mode
/// \param name Mode's name
/// \param priority Mode's priority used for storing the Mode in a specific priority group in the priority map. Default: 0
///
Mode(const std::string &name, const int priority=0);
virtual ~Mode();
std::string getName() const;
void setName(const std::string &value);
int getPriority() const;
void setPriority(int value);
///
/// \brief run is the part of a Mode which is executed by the ModeExecutor
///
virtual void run() = 0;
};
另一方面,我有另一个使用Mode 的类,称为PriorityMap,其类定义如下:
class PriorityMap
{
typedef std::pair<int, Mode *> ModeEntry;
typedef std::map<int, Mode *> PriorityGroup;
typedef PriorityGroup* PriorityGroup_Ptr;
typedef std::map<int, PriorityGroup_Ptr> Priority;
typedef Priority* Priority_Ptr;
Priority_Ptr priorities;
bool _insert(Mode *mode);
Mode *_find(const std::string &name);
public:
PriorityMap();
~PriorityMap();
void print();
void insert(Mode *mode);
template<class T> T *find(const std::string &name);
};
您可以在下面看到如何初始化和调用对象的示例:
int main ()
{
PriorityMap *priorities = new PriorityMap();
ModeSleep *m1 = new ModeSleep("Sleep10", 0, 10);
priorities->insert(m1);
ModeSleep *m2 = new ModeSleep("Sleep5", 0, 5);
priorities->insert(m2);
ModeFactorial *m3 = new ModeFactorial("Factorial20", 1, 20);
priorities->insert(m3);
priorities->print();
// Example for a correct match (both name and type) - ERROR!!!
ModeSleep *foundM2 = priorities->template find<ModeSleep>("Sleep5");
if(foundM2)
std::cout << "Found mode \"" << foundM2->getName() << "\" has time interval set to " << foundM2->getMilliseconds() << "ms" << std::endl;
// Example for correct name match but incorrect type - ERROR!!!
ModeSleep *foundM1 = priorities->template find<ModeSleep>("Factorial20");
if(foundM1)
std::cout << "Found mode \"" << foundM1->getName() << "\" has time interval set to " << foundM1->getMilliseconds() << "ms" << std::endl;
delete priorities;
return 0;
}
起初我的find() 没有任何模板内容(一旦我将原来的find() 移动为私有_find(),在template 版本的find() 中调用)。我最初的设计(现在是_find())是:
Mode *PriorityMap::_find(const std::string &name)
{
for(const auto& priorityGroup : *priorities)
for(auto& modeEntry : *(priorityGroup.second))
if(!name.compare((modeEntry.second->getName())))
return modeEntry.second;
return nullptr;
}
在运行find() 几次后,我遇到了一个问题,即我必须手动向下转换返回的指针指向Mode 的相应派生(在我的例子中只是ModeSleep 和@ 987654339@)。所以我决定为该函数添加一个模板功能并在调用它时添加一些反馈会很有用:
template<class T>
T *PriorityMap::find(const std::string &name)
{
Mode *foundMode = _find(name);
if(foundMode) {
T *foundModeCast = dynamic_cast<T *>(foundMode);
if(foundModeCast) {
std::cout << "Found mode \"" << foundModeCast->getName() << "\"" << std::endl;
return foundModeCast;
}
else {
std::cout << "Found mode \"" << foundMode->getName() << "\" however specified type is invalid! Returning NULL" << std::endl;
return nullptr;
}
}
}
正如您所见,根据我的定义,我的优先级地图中的 found 模式基于两个因素:
-
name匹配 - 给定的类型是匹配的
我在调用 find() 时遇到问题,我的构建在第一次使用时中断,并出现以下错误:
In function `main':
undefined reference to `ModeSleep *PriorityMap::find<ModeSleep>(std::string const&);'
我没有做过太多的模板成员函数,希望能得到一些反馈。如果您需要更多信息,请告知并将提供。
PS:对于那些想知道模式是如何找到基于其名称的方式的人 - 我实际上将更改我的 find() 以返回一个引用向量,因为名称是在我的情况下不是唯一的,我可以在我的优先级地图的不同位置使用相同名称的模式。现在find() 返回第一个匹配项,但足以满足本文的目的。
【问题讨论】:
标签: c++ templates member-functions