我想实现复合模式:
class Animal
{
public:
virtual void Run() = 0;
virtual void Eat(const std::string & food) = 0;
virtual ~Animal(){}
};
class Human : public Animal
{
public:
void Run(){ std::cout << "Hey Guys I'm Running!" << std::endl; }
void Eat(const std::string & food)
{
std::cout << "I am eating " << food << "; Yummy!" << std::endl;
}
};
class Horse : public Animal
{
public:
void Run(){ std::cout << "I am running real fast!" << std::endl; }
void Eat(const std::string & food)
{
std::cout << "Meah!! " << food << ", Meah!!" << std::endl;
}
};
class CompositeAnimal : public Animal
{
public:
void Run()
{
for(std::vector<Animal *>::iterator i = animals.begin();
i != animals.end(); ++i)
{
(*i)->Run();
}
}
// It's not DRY. yuck!
void Eat(const std::string & food)
{
for(std::vector<Animal *>::iterator i = animals.begin();
i != animals.end(); ++i)
{
(*i)->Eat(food);
}
}
void Add(Animal * animal)
{
animals.push_back(animal);
}
private:
std::vector<Animal *> animals;
};
你看,为了我对复合模式的简单要求,我最终写了很多相同的重复代码来遍历同一个数组。
#define COMPOSITE_ANIMAL_DELEGATE(_methodName, _paramArgs, _callArgs)\
void _methodName _paramArgs \
{ \
for(std::vector<Animal *>::iterator i = animals.begin(); \
i != animals.end(); ++i) \
{ \
(*i)->_methodName _callArgs; \
} \
}
现在我可以像这样使用它了:
class CompositeAnimal : public Animal
{
public:
// It "seems" DRY. Cool
COMPOSITE_ANIMAL_DELEGATE(Run, (), ())
COMPOSITE_ANIMAL_DELEGATE(Eat, (const std::string & food), (food))
void Add(Animal * animal)
{
animals.push_back(animal);
}
private:
std::vector<Animal *> animals
};
有没有办法通过 C++ 元编程使其“更干净”?
std::for_each 已被建议作为解决方案。我认为我们这里的问题是更一般问题的一个具体案例,让我们考虑一下我们的新宏:
#define LOGGED_COMPOSITE_ANIMAL_DELEGATE(_methodName, _paramArgs, _callArgs)\
void _methodName _paramArgs \
{ \
log << "Iterating over " << animals.size() << " animals"; \
for(std::vector<Animal *>::iterator i = animals.begin(); \
i != animals.end(); ++i) \
{ \
(*i)->_methodName _callArgs; \
} \
log << "Done" \
}
看起来不能用 for_each 代替
看看 GMan 的优秀答案,这部分 C++ 绝对不平凡。就个人而言,如果我们只是想减少样板代码的数量,我认为宏可能是适合这种特定情况的正确工具。
GMan 建议 std::mem_fun 和 std::bind2nd 返回仿函数。不幸的是,这个 API 不支持 3 个参数(我不敢相信像这样的东西被发布到 STL 中)。
为了便于说明,下面是使用 boost::bind 的委托(delegate)函数:
void Run()
{
for_each(boost::bind(&Animal::Run, _1));
}
void Eat(const std::string & food)
{
for_each(boost::bind(&Animal::Eat, _1, food));
}
最佳答案
我不确定我是否真的看到问题本身。为什么不是这样的:
void Run()
{
std::for_each(animals.begin(), animals.end(),
std::mem_fun(&Animal::Run));
}
void Eat(const std::string & food)
{
std::for_each(animals.begin(), animals.end(),
std::bind2nd(std::mem_fun(&Animal::Eat), food));
}
还不错。
如果你真的想摆脱(小)样板代码,添加:
template <typename Func>
void for_each(Func func)
{
std::for_each(animals.begin(), animals.end(), func);
}
作为私有(private)实用程序成员,然后使用:
void Run()
{
for_each(std::mem_fun(&Animal::Run));
}
void Eat(const std::string & food)
{
for_each(std::bind2nd(std::mem_fun(&Animal::Eat), food));
}
简洁一点。无需元编程。
事实上,元编程最终会失败。您正在尝试生成以文本方式定义的函数。元编程无法生成文本,因此您将不可避免地在某处使用宏来生成文本。
在下一级别,您将编写函数,然后尝试取出样板代码。 std::for_each 做得很好。当然,正如已经证明的那样,如果您发现 重复太多,也请将其排除在外。
响应评论中的 LoggedCompositeAnimal 示例,您最好的选择是制作类似于:
class log_action
{
public:
// could also take the stream to output to
log_action(const std::string& pMessage) :
mMessage(pMessage),
mTime(std::clock())
{
std::cout << "Ready to call " << pMessage << std::endl;
}
~log_action(void)
{
const std::clock_t endTime = std::clock();
std::cout << "Done calling " << pMessage << std::endl;
std::cout << "Spent time: " << ((endTime - mTime) / CLOCKS_PER_SEC)
<< " seconds." << std::endl;
}
private:
std::string mMessage;
std::clock_t mTime;
};
主要是自动记录操作。然后:
class LoggedCompositeAnimal : public CompositeAnimal
{
public:
void Run()
{
log_action log(compose_message("Run"));
CompositeAnimal::Run();
}
void Eat(const std::string & food)
{
log_action log(compose_message("Eat"));
CompositeAnimal::Eat(food);
}
private:
const std::string compose_message(const std::string& pAction)
{
return pAction + " on " +
lexical_cast<std::string>(animals.size()) + " animals.";
}
};
就像那样。 关于lexical_cast的信息.
关于C++模板元编程功夫挑战(替换一个宏函数定义),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3306113/
我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何
我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我正在使用puppet为ruby程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这
在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg
我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun