首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++11 / lambda函数&函数指针

C++11 / lambda函数&函数指针
EN

Stack Overflow用户
提问于 2013-12-16 23:41:10
回答 4查看 377关注 0票数 1

好吧,也许我的问题是有点委屈。

我试图找到一个优雅的解决方案,以减少以下样板代码,每次我想修改一个对象的一部分,该部分只能通过const Getter和非const Setter访问。

代码语言:javascript
复制
Content c = container.GetContent();
c.SetX(3); 
container.SetContent(c);

我知道我可以有一个不受欢迎的人,但我想暂时坚持下去。

因此,我尝试使用lambdas,目前有以下实现:

代码语言:javascript
复制
#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更简洁,但它们不会编译。我想知道是否有希望使他们汇编。

有人能帮忙吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-12-16 23:50:59

可以使用模板启用方法3:

代码语言:javascript
复制
template<typename F>
void ChangeContent(F function)
{
    function(mContent);
}

这将允许您传递任何可调用的(例如函子)。

另一种(C++03)方法是为Set方法实现fluent接口:

代码语言:javascript
复制
// 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;
}

并以下列方式使用:

代码语言:javascript
复制
{
    //Fluent interface
    container.SetContent( container.GetContent().SetX(111) );
    std::cout << "x=" << container.GetContent().GetX() << std::endl;
}
票数 2
EN

Stack Overflow用户

发布于 2013-12-16 23:50:57

您的问题是,您试图将一个临时对象作为引用传递:从此声明中删除&,它将工作:

代码语言:javascript
复制
void ChangeContent(ContentFunctionChanger &function)

(您还需要在一个地方将func2重命名为func )。通过引用传递函数指针实际上没有任何意义。这样做只会增加另一个间接方向,而没有任何好处,不必要的间接方向往往只会花费时间。

只是为了解释临时表达式的来源: lambda表达式的类型是每个lambda表达式的唯一类型。如果lambda函数有空捕获,则可以将其转换为函数指针。在第一段代码中,您显式地执行了这个转换,生成了一个可以绑定到引用的lvalue。在另外两种情况下,您依赖于一个隐式转换,它产生的值和rvalue不能绑定到一个非const引用(也就是说,可以通过在&前面添加const来解决这个问题,但是额外的间接方向仍然是没有意义的)。

票数 3
EN

Stack Overflow用户

发布于 2013-12-16 23:54:45

使用完全不同的方向,让SetX返回对对象的引用,然后您可以链接您的参数:

代码语言:javascript
复制
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复制内容的简单情况下,只需创建一个新的:

代码语言:javascript
复制
container.SetContent( Content( 3)) ;

或者在更复杂的情况下,如果存在一些有价值的状态,则添加一个临时对象:

代码语言:javascript
复制
container.SetContent( Content( container.getContent()).setX( 3) ) ;

谢天谢地,我认为getter/setter的趋势正在下降。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20623211

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档