Как пройти по лямбде в C ++ 0x? - PullRequest
0 голосов
/ 14 июля 2011

Кажется, что способ создания объектов в C ++ 0x, избегающий копирования / перемещения (особенно для объектов, выделенных большим стеком), - это «проход по лямбде».

См. Следующий код :

#include <iostream>

#define LAMBDA(x) [&] { return x; }

class A
{
public:
  A() {};
  A(const A&) { std::cout << "Copy "; }
  A(A&&) { std::cout << "Move "; }
};

class B1
{
public:
  B1(const A& a_) : a(a_) {}
  B1(A&& a_) : a(std::move(a_)) {}
  A a;
};

class B2
{
public:
  B2(const A& a_) : a(a_) {}
  B2(A&& a_) : a(std::move(a_)) {}
  template <class LAMBDA_T>
  B2(LAMBDA_T&& f, decltype(f())* dummy = 0) : a(f()) {}
  A a;
};

int main()
{
  A a;
  std::cout << "B1 b11(       a ): ";
  B1 b11(a);
  std::cout << std::endl;
  std::cout << "B2 b12(LAMBDA(a)): ";
  B2 b12(LAMBDA(a));
  std::cout << std::endl;
  std::cout << std::endl;

  std::cout << "B1 b21(       std::move(a) ): ";
  B1 b21(std::move(a));
  std::cout << std::endl;
  std::cout << "B2 b22(LAMBDA(std::move(a))): ";
  B2 b22(LAMBDA(std::move(a)));
  std::cout << std::endl;
  std::cout << std::endl;

  std::cout << "B1 b31((       A() )): "; 
  B1 b31((A())); 
  std::cout << std::endl;
  std::cout << "B2 b32((LAMBDA(A()))): ";
  B2 b32((LAMBDA(A()))); 
  std::cout << std::endl;
  std::cout << std::endl;
}

Что выводит следующее:

B1 b11(       a ): Copy 
B2 b12(LAMBDA(a)): Copy 

B1 b21(       std::move(a) ): Move 
B2 b22(LAMBDA(std::move(a))): Move 

B1 b31((       A() )): Move 
B2 b32((LAMBDA(A()))): 

Обратите внимание, что «проход по лямбде» удаляет движение в случае, когда параметр, как я полагаю, называется «prvalue»".

Обратите внимание, что кажется, что подход" проход по лямбде "помогает только тогда, когда параметр имеет значение" prvalue ", но в других случаях он не причиняет вреда.

Есть лив любом случае, чтобы заставить функции принимать параметры «прохода через лямбду» в C ++ 0x, это лучше, чем клиенту, который должен обернуть свои параметры в сами лямбда-функции?(кроме определения прокси-макроса, который вызывает функцию).

Ответы [ 2 ]

3 голосов
/ 14 июля 2011

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

class super_expensive_type {
public:
    struct token_t {} static constexpr token = token_t {};

    super_expensive_type(token_t);
}
constexpr super_expensive_type::token_t super_expensive_type::token;

class user {
public:
    template<typename... Args>
    explicit
    user(Args&&... args)
        : member { std::forward<Args>(args)... }
    {}

private:
    super_expensive_type member;
};

// ...

// only one construction here
user { super_expensive_type::token };

super_expensive_type moved_from = ...;
// one move
user { std::move(moved_from) };

super_expensive_type copied_from = ...;
// one copy
user { copied_from };

Использование лямбд не может быть лучше, чем это, потому что должен быть возвращен результат выражения в теле лямбды.

2 голосов
/ 14 июля 2011

Есть фундаментальная проблема с тем, что вы делаете.Вы не можете заколдовать объект в существование.Переменная должна быть:

  1. Построена по умолчанию
  2. Построена копия
  3. Построена конструкция
  4. Построена с использованием другого конструктора.

4 вне стола, так как вы определили только первые три.Ваши конструкторы копирования и перемещения оба печатают вещи.Таким образом, единственный вывод, который можно сделать, состоит в том, что, если ничего не печатается, объект создается default .IE: заполнено ничем .

Короче говоря, ваш механизм передачи на основе Lambda, похоже, вообще ничего не передает.


После дальнейшего анализаЯ вижу, что происходит.Ваша лямбда на самом деле не принимает значение по ссылке;это создание значения.Если вы развернете макрос, то получите следующее:

B2 b32(([&] {return A()}));

Он создает временный;это на самом деле ничего не берет по ссылке.Так что я не уверен, что вы можете считать это "прохождением" чего-либо.Все, что вы делаете, это создаете функцию, которая создает объект.Вы также можете легко передать аргументы для конструктора B2::a в конструктор B2 и использовать его для создания объекта, и это даст вам тот же эффект.

Выне передавая значение.Вы создаете функцию, которая всегда будет создавать один и тот же объект.Это не очень полезно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...