良好实践:从lambda构造一个复杂成员

Good practice : construction of a complex member from a lambda

本文关键字:一个 成员 复杂 lambda      更新时间:2023-10-16

我有时会在我的类中使用这种模式:

class Variant;
struct Foo
{
  int x; 
  int y;
};
struct Bar
{
  int first() const; 
  int second() const; 
};
class Bar
{
  public:
    Bar(Variant v)
    {
       // For brevity there are no 
       // tests in this sample code
       Bar aBar = v.get<Bar>();  // Variant::get is a slow operation
       m_theFoo.x = aBar.first();
       m_theFoo.x = aBar.second();
    }
  private:
    Foo m_theFoo;
};

我宁愿在初始化列表中初始化m_theFoo。但是,我不想像这样两次调用Variant::get,因为它可能是一个很慢的操作:

Bar(Variant v):
   m_theFoo{v.get<Bar>().first(), v.get<Bar>().second()}
{
}

所以我想到了这个:

Bar(Variant v):
    m_theFoo{[&] () { 
            Bar aBar = v.get<Bar>();
            return Foo{aBar.first(), aBar.second()};
        }()
    }  
{
}

基本上,初始化是由被调用的lambda完成的,并返回初始化的成员。

我想知道这听起来是否像一个好/坏的做法,如果有这个初始化方法的缺点。例如,lambda实例化的权重是多少?

让它像这样成为一个无状态的lambda会更好吗?

Bar(Variant v):
    m_theFoo{[] (const Variant& v_sub) { 
            Bar aBar = v_sub.get<Bar>();
            return Foo{aBar.first(), aBar.second()};
        }(v)
    }  
{
}

只需将您的初始化转发到一个函数-您可以获得所有的好处,而不会因为有点神秘而使您的代码看起来很奇怪:

Bar(Variant v)
: m_theFoo(makeFoo(v))
{ }

:

Foo makeFoo(const Variant& v) {
    Bar theBar = v.get<Bar>();
    return Foo{theBar.first(), theBar.second()};
}