好吧,也许我的问题是有点委屈。
我试图找到一个优雅的解决方案,以减少以下样板代码,每次我想修改一个对象的一部分,该部分只能通过const Getter和非const Setter访问。
Content c = container.GetContent();
c.SetX(3);
container.SetContent(c);我知道我可以有一个不受欢迎的人,但我想暂时坚持下去。
因此,我尝试使用lambdas,目前有以下实现:
#include <iostream>
class Content
{
public:
Content(int x) :mX(x) {}
const int GetX() const
{
return mX;
}
void SetX(const int &x)
{
mX = x;
}
private:
int mX;
};
//for clarity ContentFunctionChanger is a typedef for any function of type : void f(Content &)
typedef void (*ContentFunctionChanger)(Content &);
class Container
{
public:
Container(const Content &c) :mContent(c) {}
const Content & GetContent() const
{
return mContent;
}
void SetContent(const Content &c)
{
mContent = c;
}
void ChangeContent(ContentFunctionChanger &function)
{
(*function)(mContent);
}
private:
Content mContent;
};
int main()
{
Content content(1);
Container container(content);
std::cout << "x=" << container.GetContent().GetX() << std::endl;
{
//Classic method using Get() then Set()
Content c = container.GetContent();
c.SetX(3);
container.SetContent(c);
std::cout << "x=" << container.GetContent().GetX() << std::endl;
}
{
//Method 1 : with a named lambda function whose type is written at the declaration
//It works, but it is not concise
ContentFunctionChanger func = [] (Content & c) { c.SetX(5); };
container.ChangeContent(func);
std::cout << "x=" << container.GetContent().GetX() << std::endl;
}
/*
{
//Method 2 : with a named lambda function whose type is not written (using auto)
//It will not compile...
auto func = [] (Content & c) { c.SetX(7); };
container.ChangeContent(func);
std::cout << "x=" << container.GetContent().GetX() << std::endl;
}
{
//Method 3: with an anonmymous lambda.
//Concise enough, but it does not compile either...
container.ChangeContent([] (Content & c) { c.SetX(9); } );
std::cout << "x=" << container.GetContent().GetX() << std::endl;
}
*/
return 0;
}我的问题是,方法2和方法3更简洁,但它们不会编译。我想知道是否有希望使他们汇编。
有人能帮忙吗?
发布于 2013-12-16 23:50:59
可以使用模板启用方法3:
template<typename F>
void ChangeContent(F function)
{
function(mContent);
}这将允许您传递任何可调用的(例如函子)。
另一种(C++03)方法是为Set方法实现fluent接口:
// kind of a functional set — if we want Set to constant, we need to return a new object
Content SetX(const int &x) const
{
Content ret = *this;
ret.mX = x;
return ret;
}并以下列方式使用:
{
//Fluent interface
container.SetContent( container.GetContent().SetX(111) );
std::cout << "x=" << container.GetContent().GetX() << std::endl;
}发布于 2013-12-16 23:50:57
您的问题是,您试图将一个临时对象作为引用传递:从此声明中删除&,它将工作:
void ChangeContent(ContentFunctionChanger &function)(您还需要在一个地方将func2重命名为func )。通过引用传递函数指针实际上没有任何意义。这样做只会增加另一个间接方向,而没有任何好处,不必要的间接方向往往只会花费时间。
只是为了解释临时表达式的来源: lambda表达式的类型是每个lambda表达式的唯一类型。如果lambda函数有空捕获,则可以将其转换为函数指针。在第一段代码中,您显式地执行了这个转换,生成了一个可以绑定到引用的lvalue。在另外两种情况下,您依赖于一个隐式转换,它产生的值和rvalue不能绑定到一个非const引用(也就是说,可以通过在&前面添加const来解决这个问题,但是额外的间接方向仍然是没有意义的)。
发布于 2013-12-16 23:54:45
使用完全不同的方向,让SetX返回对对象的引用,然后您可以链接您的参数:
Content & SetX(const int &x)
{
mX = x;
return * this ;
}
...
container.SetContent( container.GetContent().setX( 3)) ;但是,在这种情况下,container.GetContent()返回一个const,因此您甚至不能在它上调用setX,这就引出了一个问题:如果您必须创建一个新的对象来修改它,那么为什么还要调用GetContent()呢?
虽然其他人修改了setX的行为以返回一个新对象,但我认为这不符合动词的要求。我希望set*修改一个对象,而不是返回一个新的对象。下面是我如何处理保存setX的意义并处理来自getter的const值的问题。
在不从Content复制内容的简单情况下,只需创建一个新的:
container.SetContent( Content( 3)) ;或者在更复杂的情况下,如果存在一些有价值的状态,则添加一个临时对象:
container.SetContent( Content( container.getContent()).setX( 3) ) ;谢天谢地,我认为getter/setter的趋势正在下降。
https://stackoverflow.com/questions/20623211
复制相似问题