2016-04-21 7 views
3

Я новичок в C++, недавно появившемся от Swift. Есть ли способ получить более короткий лямбда-синтаксис?C++ более короткий синтаксис лямбда

У меня есть много линий, как:

columns = { 
    Col(_("Name"), "string", [] (Person *p) { 
           return p->Name(); 
           }), 
    Col(_("Age"), "int", [] (Person *p) { 
           return p->Age(); 
           }), 
    Col(_("Bank"), "string", [&banks] (Person *p) { 
          return banks.lookUp(p->Identifier()).Name; 
          }), 
    //..etc.. 
}; 

Некоторые из колонок требуют более лямбды, но как это синтаксис для написания лямбда составляет около тех пор, пока содержание это сам.

Можно ли вообще уменьшить синтаксис лямбда? (Скажем, с помощью неявного аргумента или неявно возвращает последнее заявление)

Например, в Swift я мог бы сделать что-то вроде этого, и это было бы то же самое:

Col(_("Age"), "int", { $0.Age() }), 

EDIT: Добавлен столбец банка в качестве примера более сложный.

+1

Если вы используете одну и ту же лямбду снова и снова, вы можете сохранить ее в переменной, а затем использовать переменную вместо лямбда. – NathanOliver

+0

_ «Может ли синтаксис лямбда вообще быть уменьшен?» _ Ну, спросите [ISO C++ commitee] (https://isocpp.org/std/the-committee). –

+0

@NathanOliver, я знаю, но они не такие же лямбда? –

ответ

5

Может синтаксис лямбда быть уменьшен на всех?

Я так не считаю. Основные компоненты lambda функции для ваших нужд являются:

[ capture-list ] (params) { body } 

Вы его в качестве минимальной форме, как это возможно с C++ 11.

+2

Сторона примечания: самая короткая лямбда - '[] {}' - Параметры являются необязательными. –

+0

@ DieterLücking, ему, кажется, нужен параметр 'p' в теле функции. –

2

Вместо того, чтобы пропускать лямбда вообще, вы должны переделать Col_, чтобы он мог принимать указатели на элементы и знать, что с ними делать (например, обернув их в std::mem_fn). Таким образом, вы можете просто написать:

columns = { 
    Col(_("Name"), "string", &Person::Name), 
    Col(_("Age"), "int", &Person::Age), 
    //..etc.. 
}; 
+0

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

+0

@Jonathan. Почему он «работает» только для простых? Я не говорил * только * принимать указатели на членов, просто расширять его, чтобы работать для указателей на членов тоже. – Barry

4

Если вы всегда вызов функции-члена, вы можете использовать mem_fn:

Col(_("Name"), "string", std::mem_fn(&Person::Name)), 

А mem_fn работ при пропускании либо указатель или ссылку на объект тип.

1

если у вас есть C++ 14 (и если вы исходите из быстрого, вы, вероятно, делаете), то вы можете заменить тип аргумента на auto. Кроме того, несобранные lambdas не требуют места (они эквивалентны указателю на функцию), поэтому нет производительности, если вы просто предварительно определяете их и используете копию в своем инициализаторе.

// this will return the Name of any pointee that has a Name() method 
auto get_name = [](auto*p) { return p->Name(); } 
auto get_age = [](auto*p) { return p->Age(); } 

columns = { 
    Col(_("Name"), "string", get_name), 
    Col(_("Age"), "int", get_age), 
    //..etc.. 
}; 
0

Вы могли #define макрос для этого, но это немного hackish and evil.

#define GEN_LAMBDA(arg) [](Person *p){ return p->arg();} 

columns = { 
    Col(_("Name"), "string", GEN_LAMBDA(Name)), 
    Col(_("Age"), "int", GEN_LAMBDA(Age)), 
    //..etc.. 
}; 
+0

Yup Я думал об этом: '#define LBD (код) [] (Person * $ 0) {код возврата; } 'и был почти болен :) –

+0

@ Джонатан. Мой работает, верно? – Zereges

+0

Я не пробовал, но поскольку это в основном то же, что и я, я так и предполагаю. –

0

Вы могли бы попробовать подход к проектированию политики на основе путем определения вашей политики для каждого члена данных

enum FieldID {AGE, NAME, ID}; 
template<FieldID fid> auto get(Person &p); 
template<FieldID fid> std::string getType(); 
template<FieldID fid> std::string getFieldName(); 

template <> auto get<AGE>(Person &p) {return p.Age();} 
template <> auto get<NAME>(Person &p) {return p.Name();} 
template <> auto get<ID>(Person &p) {return p.ID();} 

template <> std::string getType<AGE>() {return "int";} 
template <> std::string getType<NAME>() {return "string";} 
template <> std::string getType<ID>() {return "size_t";} 

template <> std::string getFieldName<AGE>() {return "Age";} 
template <> std::string getFieldName<NAME>() {return "Name";} 
template <> std::string getFieldName<ID>() {return "Bank";} 

и ваш код будет выглядеть следующим образом

Col(_(getFieldName<AGE>()), getType<AGE>(), get<AGE>(p) 
+0

В настоящее время каждый столбец представлен перечислением, и проблема в том, что некоторые столбцы генерируются динамически на основе других данных. –

0

Использование C++ 14 и макросы, вы может близко имитировать синтаксис arrow functions из javascript (ES6).

На самом деле, как правило, этого достаточно, чтобы захватить все по ссылке.Тип аргумента может быть установлен на автоматический, тип возврата может быть опущен. Таким образом, короткая версия, что C++ 14 позволяет нам это:

auto f = [&](auto x, auto y) { return x + y; }; 

Очевидно, что это может быть легко превращен в макросы:

#define _L2(a, b, res) [&](auto a, auto b) { return res; } 
#define _S2(res) _L2(_0, _1, res) 

_L2 макрос создает лямбда с двумя заданными пользователем параметрами. Макрос _S2 создает лямбда с параметрами с именем _0 и _1. Наконец, мы можем использовать this answer для перегрузки макроса _L по количеству аргументов. Я понятия не имею, как вывести количество аргументов для _S через макросы.

Теперь мы можем написать что-то вроде:

auto g = _L(x, y, x + y); //std::plus 
auto g = _S2(_0 + _1);  //std::plus 

Вы можете даже сделать некоторые сумасшедшие вещи, как:

//turns unary accessor function into binary comparator functor 
auto compByKey = _L(f, _L(x, y, f(x) < f(y))); 
//sort vector<string> by length 
sort(arr.begin(), arr.end(), compByKey(_L(x, x.length()))); 

Действительно, синтаксис до сих пор не ясно, как в оригинале, Javascript или быстры , но он намного короче. Теперь проблема состоит в том, чтобы запомнить все виды lambdas, которые мы определили =) В любом случае, библиотека STL не приветствует программирование функционального стиля ...

Полный код доступен on ideone.