2014-12-10 3 views
1

Давайте посмотрим реальный пример из жизни:лямбда возвращение в списке инициализатора

class RuleNameConverter { 
public: 
    RuleNameConverter(const boost::property_tree::ptree& pt); 
    int toIdentifier(const std::string& name) const; 
    std::string toName(const int id) const; 

private: 
    using Bimap = boost::bimap<std::string, int>; 
    Bimap bimap_; 
}; 

Если конструктор это:

RuleNameConverter::RuleNameConverter(const boost::property_tree::ptree& pt) { 
    for (const auto& item : pt) { 
     if (item.first == "rule") { 
      auto name = item.second.get <std::string> ("<xmlattr>.name"); 
      auto id = item.second.get<int>("<xmlattr>.id"); 
      bimap_.insert(Bimap::value_type { name, id }); 
     } 
    } 
} 

Предположим, вы хотите константный атрибут в члена:

... 
    const Bimap bimap_; 
}; 

Вы должны инициализировать его в списке инициализаторов, а не в конструкторе b оды. Инициализация не является тривиальной, поэтому вы должны делегировать функцию для вычисления ее значения. Вы можете использовать значение, возвращаемое лямбда, принимая преимущества этого шага семантики (без копирования временных объектов):

RuleNameConverter::RuleNameConverter(const boost::property_tree::ptree& pt) : 
     bimap_ { [&pt]() { 
      Bimap results; 
      for (const auto& item : pt) { 
       if (item.first == "rule") { 
        auto name = item.second.get <std::string> ("<xmlattr>.name"); 
        auto id = item.second.get<int>("<xmlattr>.id"); 
        results.insert(Bimap::value_type {name, id}); 
       } 
      } 
      return results; 
     }() } { 
} 

Существуют ли какие-либо недостатки в использовании этого метода? Это стоит того? Я нахожу его немного менее удобочитаемым, но как насчет производительности?

+0

Хм. Я бы дважды проверял правила области захвата только для того, чтобы убедиться, что там нет причуды (вы находитесь в странном контексте) - возможно, нет, после 2 стандартных версий, особенно на практике. – Yakk

+0

Изменить 'return results;' to 'return std :: move (results);'. Да, у компиляторов есть RVO, но этот способ переводится многословным. – GreenScape

+0

@GreenScape Я помню, что стандарт C++ 11 требует RVO в этом случае, правильно? –

ответ

2

Производительность, это не должно иметь большого значения. Вы не копируете вокруг каких-либо объектов Bitmap, и конструкция вашей лямбда не должна занимать сколько-нибудь заметного времени.

Но для удобства чтения, я хотел бы создать статическую функцию-член вместо лямбда здесь:

class RuleNameConverter { 
public: 
    RuleNameConverter(const boost::property_tree::ptree& pt); 
private: 
    static Bitmap createBitmap(const boost::property_tree::ptree& pt); 
}; 

RuleNameConverter::RuleNameConverter(const boost::property_tree::ptree& pt) : 
    bimap_ { createBitmap(pt) } { 
} 

Bitmap RuleNameConverter::createBitmap(const boost::property_tree::ptree& pt) { 
    Bimap results; 
    for (const auto& item : pt) { 
     if (item.first == "rule") { 
      auto name = item.second.get <std::string> ("<xmlattr>.name"); 
      auto id = item.second.get<int>("<xmlattr>.id"); 
      results.insert(Bimap::value_type {name, id}); 
     } 
    } 
    return results; 
} 

Если вам необходимо инициализировать несколько пользователей, используя вспомогательные функции, создавая новый лямбда для каждого члена приводит к неосновательный беспорядок в списке инициализаторов конструктора, но некоторые вспомогательные функции не должны иметь эту проблему. Кроме того, если вы добавляете перегрузки конструктора, createBitmap может быть легко вызван из нескольких конструкторов.

В качестве альтернативы используйте обычную функцию, не являющуюся членом, если тело createBitmap не имеет особого отношения к вашему RuleNameConverter.

1

Вы можете обернуть Bimap в другом классе, где его конструктор будет иметь то же тело, что и лямбда.

Я не вижу, как использование лямбда во избежание поверхностного класса в этом случае приведет к любым проблемам, за исключением того, что его намерение, пожалуй, менее понятно, потому что у него нет имени (но это так с симпатичным много любой лямбда).

Смежные вопросы