我需要当前工作流程的帮助,尽管一切都可以按预期进行,但我想使结构更坚固。
我有一个应用程序,在其中我可以按字符串文字更改数据。
WAVEFRONT*TREEVIEW*Main$Text*GEOMETRY*TEXT SET TEXT ABCD
如图所示,其中“ Main $ Text”是树结构数据项的路径。
1)第一步->我有一个类来处理命令字符串并采取适当的措施。
int SumCommandInterface::receiveCommand(std::string stdtsrCommand , const QModelIndex & RootIndex, TreeModel *myModel)
{
std::vector<std::string> vectorStrCommand;
std::vector<std::string> vectorStrStarSplit;
std::vector<std::string> vectorStrContainerNames;
boost::algorithm::trim(stdtsrCommand);
boost::split(vectorStrCommand, stdtsrCommand, boost::is_any_of(" "), boost::token_compress_on);
boost::split(vectorStrStarSplit, vectorStrCommand[0], boost::is_any_of("*"), boost::token_compress_on);
if (vectorStrStarSplit[1] == "TREEVIEW") // for tree view
{
if (vectorStrCommand.size() < 4)
return -1;
boost::split(vectorStrContainerNames, vectorStrStarSplit[2], boost::is_any_of("$"), boost::token_compress_on);
TreeItem* itm;
QModelIndex Index = RootIndex;
for (auto &strName : vectorStrContainerNames)
{
if (!getTreeItem(strName, Index, myModel, &itm))
{
return 0;
}
Index = myModel->indexForTreeItem(itm);
}
PluginTypeLookUp lookUp = lookUpPluginMap[vectorStrStarSplit[3]];
Container *cont = itm->GetContainer();
switch (lookUp)
{
case PluginTypeLookUp::GEOMTERY: // This can be function , texture etc, currently only showing code for geometry
{
Geometry *geom = cont->GetGeometry();
if(vectorStrCommand[2] == "TEXT" )
setFontPluginParam< Geometry , std::string >( geom, vectorStrCommand[2], vectorStrCommand[3]);
if (vectorStrCommand[2] == "USESHADOW")
setFontPluginParam< Geometry , bool >(geom, vectorStrCommand[2], (vectorStrCommand[3] == "0" ? false : true) );
if (vectorStrCommand[2] == "FONTSIZE" || vectorStrCommand[2] == "SHADOWDIRECTION")
setFontPluginParam< Geometry, int >(geom, vectorStrCommand[2], std::stoi(vectorStrCommand[3]) );
if (vectorStrCommand[2] == "SHADOWDISTANCE" || vectorStrCommand[2] == "SHADOWOPACITY" || vectorStrCommand[2] == "KERNING" )
setFontPluginParam< Geometry, float >(geom, vectorStrCommand[2], std::stof(vectorStrCommand[3]));
}
break;
case PluginTypeLookUp::TEXTURE:
{
Sum_Texture_2D *texture;
texture = cont->GetTexturePointer();
if(vectorStrCommand[2] == "TEXTUREPATH" )
setTexturePluginParam< Sum_Texture_2D, std::string >(texture, vectorStrCommand[2], vectorStrCommand[3]);
if (vectorStrCommand[2] == "POSITIONX" || vectorStrCommand[2] == "POSITIONY" || vectorStrCommand[2] == "POSITIONZ" || vectorStrCommand[2] == "SCALINGX" || vectorStrCommand[2] == "SCALINGY" || vectorStrCommand[2] == "SCALINGZ" || vectorStrCommand[2] == "ROTATIONX" || vectorStrCommand[2] == "ROTATIONY" || vectorStrCommand[2] == "ROTATIONZ ")
{
setTexturePluginParam< Sum_Texture_2D, float >(texture, vectorStrCommand[2], std::stof(vectorStrCommand[3]));
}
break;
}
default:
break;
}
return 1;
}
return 0;
}
我在命令中传递了几何参数,基于此我有一个if条件。
例如对于USESHADOW,命令看起来像。
WAVEFRONT*TREEVIEW*AMain$Text*GEOMETRY*TEXT SET USESHADOW 1
如果Geometry参数为TEXT,则命令将如下所示。
WAVEFRONT*TREEVIEW*AMain$Text*GEOMETRY*TEXT SET TEXT ABC
case PluginTypeLookUp::GEOMTERY: // This can be function , texture
etc, currently only showing code for geometry
{
Geometry *geom = cont->GetGeometry();
if(vectorStrCommand[2] == "TEXT" )
setFontPluginParam< Geometry , std::string >( geom, vectorStrCommand[2], vectorStrCommand[3]);
if (vectorStrCommand[2] == "USESHADOW")
setFontPluginParam< Geometry , bool >(geom, vectorStrCommand[2], (vectorStrCommand[3] == "0" ? false : true) );
if (vectorStrCommand[2] == "FONTSIZE" || vectorStrCommand[2] == "SHADOWDIRECTION")
setFontPluginParam< Geometry, int >(geom, vectorStrCommand[2], std::stoi(vectorStrCommand[3]) );
if (vectorStrCommand[2] == "SHADOWDISTANCE" || vectorStrCommand[2] == "SHADOWOPACITY" || vectorStrCommand[2] == "KERNING" )
setFontPluginParam< Geometry, float >(geom, vectorStrCommand[2], std::stof(vectorStrCommand[3]));
}
break;
我面临的当前问题是,如果我有30个不同的几何参数,则如果条件需要添加30个。
如果我添加更多的几何类型,我将再次需要重新访问此代码并添加更多参数。
我能以更优雅的方式处理此步骤吗?
最佳答案
基本的映射查找。这些使基于表的菜单系统和简单的解析器变得非常出色。它们可能不是最快的,但是代码确实很简单1,易于阅读并且很难搞砸。添加新命令或关键字就像在map
的初始化程序中添加另一行一样简单。
所有你需要的是:std::map
链接输入文本与所需的行为。
一堆函数都具有相同的原型,可以执行所需的行为。当行为简单时,Lambda表达式是一个不错的选择,因为它们会将所有相关代码都放在一个位置
开始了!
#include <map>
#include <functional>
#include <string>
#include <iostream>
#include <vector>
// standing in for setFontPluginParam
template<class T>
void template_func(const std::string& name, const T & data)
{
std::cout << name << ":" << data << std::endl;
}
// functions to convert the data to the correct type for template_func
void text_func(const std::string & name, const std::string & text)
{
std::cout << "text_func "; // make output easier to interpret
template_func(name, text); // call correct template specialization
}
void int_func(const std::string & name, const std::string & num)
{
std::cout << "int_func ";
template_func(name, std::stoi(num));
}
// maps the name to the function. Note: If you're not messing around with lambdas or
// member functions, an old school function pointer may work better that std::function
std::map<std::string, std::function<void(const std::string &, const std::string &)>> call_function =
{
{"TEXT", text_func},
{"INT", int_func},
// same as above, but with a lambda expression to keep everything all in one place
{"DOUBLE", [](const std::string & name, const std::string & num) {
std::cout << "double_func ";
template_func(name, std::stod(num));
}}
};
void demo(const std::vector<std::string> & vectorStrCommand)
{
// uses map to look up correct function, then calls it
// This is basically all that's left of the if/else if chain
call_function[vectorStrCommand[2]](vectorStrCommand[2], vectorStrCommand[3]);
}
int main()
{
demo({"whatever", "whatever", "INT", "42"});
demo({"whatever", "whatever", "TEXT", "I am the very model of a modern major general..."});
demo({"whatever", "whatever", "DOUBLE", "3.14"});
}
1因为它很简单,所以最适合简单的事情。不要尝试编写像这样的C ++编译器。
关于c++ - 如何使当前的编码结构更灵活,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57882270/