草庐IT

具有模板化函数的 C++ 调度表

coder 2024-02-05 原文

我在一些 C++ 代码中有一个调度表。它将标签映射到可以处理这些标签的函数。在第一个版本中,它采用接受两个字符串并返回一个字符串的函数。字符串是序列化的 protobuf。

map<string, function<string(const string& serialised_1,
                            const string& serialised_2)>> converters = {
...
{ 'dog', ProcessTwoDogs },
{ 'cat', ProcessTwoCats },
...
};

这里的转换器函数看起来像这样

string ProcessTwoDogs(const string& dog_1_str, const string& dog_2_str);

在实现了相当多的此类转换器之后,我意识到它们通常超过了一半的样板文件:错误检查、反序列化、序列化等。因此我编写了一个快速模板,极大地简化了我的代码:

template <typename ProtoT>
std::string ConvertProtos(
    const std::string& proto_str_a,
    const std::string& proto_str_b,
    std::function<ProtoT(const ProtoT&, const ProtoT&)> convert_proto) {
    ProtoT proto_a = ...;
    ProtoT probo_b = ...;
    // and various error checks.
    ProtoT proto_out = convert_proto(proto_a, proto_b);
    // some more checks, and serialise to proto_out_str.
    return proto_out_str;
}

现在 convert_proto() 看起来像这样:

Dog ProcessTwoDogs(const Dog& dog_1, const Dog& dog_2) { ... }

这很好,但是现在我破坏了调度表,因为每个动物处理器都有不同的签名,因为 DogCat 都是 protobufs但除此之外是无关的。我不知道如何在不求助于很长一段 if ... else if .... 的情况下制作调度表。

我想要的是这样一张 map :

// Doesn't compile.
map<string, 
   template<typename ProtoT>function<ProtoT(const ProtoT&, const ProtoT&)>>

然后是我的函数,它使用了调度表,目前是这样的

auto processor = the_map.at(tag);
string new_string = processor(string_1, string_2);

成为

auto processor = the_map.at(tag);
string new_string = ConvertProtobufs(string_1, string_2, processor);

当然,一种方法是使用接受字符串的 operator() 定义一个抽象基类,然后为我的每个转换函数实现该类的一个实例。 operator() 调用一些仅在派生类中定义的函数。但现在我失去了我可能发现的可读性或简洁性方面的任何收获。

有什么建议吗?

更新

根据@felix 提出的一系列推理,我这样写:

#include <functional>
#include <iostream>
#include <map>
#include <string>

using std::cout;
using std::function;
using std::endl;
using std::map;
using std::string;

struct Dog {
    void operator()() { cout << "I am a dog." << endl; }
};
struct Cat {
    void operator()() { cout << "I am a cat." << endl; }
};

string cat = string("cat");
string dog = string("dog");

template<string& s> void fn() { cout << "I am lost" << endl; }
template<> void fn<dog>() { Dog dog; dog(); }
template<> void fn<cat>() { Cat cat; cat(); }

int main(int argc, char *argv[]) {
    (void)argc;
    (void)argv;
    fn<dog>();
    fn<cat>();
    // Oops, it all falls apart here:
    string dog1("dog");
    fn<dog1>();   // Doesn't compile, and a dog is not a dog1.
}

上面的问题是模板参数当然必须在编译时知道。当我使用来自字符串本体的 const 字符串时,这很好,但如果字符串通过数据库传递,则失败,因此查找是基于值而不是对象的动态查找。

最佳答案

你还想要map<string, function<string(const string&, const string&)>> ,您只想以不同的方式填充它:

using converter = function<string(const string&, const string&)>;

map<string, converter> converters = {
    ...
   { "dog", convert_protos(ProcessTwoDogs) },
   { "cat", convert_protos(ProcessTwoCats) },
    ...
};

现在您需要一个返回转换器的函数模板,您可以将其与任何 ProcessTwoDogs 一起使用, ProcessTwoCats你有什么。

template <typename P_Res, typename P_A, typename P_B> 
converter convert_protos(P_Res (*processor)(P_A, P_B)) {

    return [](const string& s_a, const string& s_b) -> string
       {
          // some error checks
          P_A p_a = deserialize<P_A>(s_a);
          P_B p_b = deserialize<P_B>(s_a);
          // some more error checks
          P_Res p_res = processor(p_a, p_b);
          // yet more checks
          string s_res = serialize(p_res);
          // last final checks
          return s_res;
       };
}

关于具有模板化函数的 C++ 调度表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42162577/

有关具有模板化函数的 C++ 调度表的更多相关文章

  1. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  4. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  5. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  6. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  7. ruby-on-rails - Rails 3.1 中具有相同形式的多个模型? - 2

    我正在使用Rails3.1并在一个论坛上工作。我有一个名为Topic的模型,每个模型都有许多Post。当用户创建新主题时,他们也应该创建第一个Post。但是,我不确定如何以相同的形式执行此操作。这是我的代码:classTopic:destroyaccepts_nested_attributes_for:postsvalidates_presence_of:titleendclassPost...但这似乎不起作用。有什么想法吗?谢谢! 最佳答案 @Pablo的回答似乎有你需要的一切。但更具体地说...首先改变你View中的这一行对此#

  8. ruby - 在 Ruby 中按名称传递函数 - 2

    如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

  9. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  10. ruby-on-rails - Mandrill API 模板 - 2

    我正在使用Mandrill的RubyAPIGem并使用以下简单的测试模板:testastic按照Heroku指南中的示例,我有以下Ruby代码:require'mandrill'm=Mandrill::API.newrendered=m.templates.render'test-template',[{:header=>'someheadertext',:main_section=>'Themaincontentblock',:footer=>'asdf'}]mail(:to=>"JaysonLane",:subject=>"TestEmail")do|format|format.h

随机推荐