template - c++ lambda type




So erfassen Sie std:: unique_ptr "by move" für ein Lambda in std:: for_each (2)

Ich lerne die neuen Funktionen in C ++ 11 und stieß auf dieses Problem. Ich möchte ein unique_ptr erfassen, indem ich es innerhalb eines Lambda als Argument für for_each verschiebe.

Konfiguration:

std::array<int,4> arr = {1,3,5,6};
std::unique_ptr<int> p(new int);  (*p) = 3;

Versuch 1 - funktioniert nicht, weil unique_ptr keinen Kopierkonstruktor hat. c ++ 0x gibt nicht die Syntax für die Übergabe nach Bewegung an.

std::for_each(arr.begin(), arr.end(), [p](int& i) { i+=*p; });

Versuch 2 - benutze bind, um eine verschobene Kopie von p an eine Funktion zu binden, die int & übernimmt:

std::for_each(arr.begin(), arr.end(),
     std::bind([](const unique_ptr<int>& p, int& i){
          i += (*p);
     }, std::move(p))
);

Compiler beklagt sich, dass 'result' : symbol is neither a class template nor a function template.

Der Hauptzweck der Übung besteht darin, zu verstehen, wie eine bewegliche Variable in einem Lambda gefangen wird, das für die spätere Verwendung zwischengespeichert wird.


Update: Sie können eine bewegliche Variable in einem Lambda ab C ++ 14 abfangen.

std::for_each(arr.begin(), arr.end(), [p=std::move(p)](int& i) { i+=*p; });

Sie können eine bewegliche Variable in C ++ 11 nicht auf einfache Weise in ein Lambda aufnehmen.

Lambdas erfassen durch Kopie oder durch Referenz. std::auto_ptr eine Nur-Bewegung-Variable zu erfassen, müssen Sie sie in ein Objekt std::auto_ptr wo Kopieren => Verschieben (wie std::auto_ptr ). Das ist ein hässlicher Hack.

In Ihrem Beispiel können Sie nur per Referenz erfassen, aber wenn dies nur vereinfachter Code war, kann es möglicherweise nicht mit dem echten Code tun, was Sie wollten:

std::for_each(arr.begin(), arr.end(), [&p](int& i) { i+=*p; });

Hier ist ein Copy-Move-only-Wrapper:

template<typename T>
struct move_on_copy_wrapper
{
    mutable T value;

    move_on_copy_wrapper(T&& t):
        value(std::move(t))
    {}

    move_on_copy_wrapper(move_on_copy_wrapper const& other):
        value(std::move(other.value))
    {}

    move_on_copy_wrapper(move_on_copy_wrapper&& other):
        value(std::move(other.value))
    {}

    move_on_copy_wrapper& operator=(move_on_copy_wrapper const& other)
    {
        value=std::move(other.value);
        return *this;
    }

    move_on_copy_wrapper& operator=(move_on_copy_wrapper&& other)
    {
        value=std::move(other.value);
        return *this;
    }

};

Sie können es dann wie folgt verwenden:

int main()
{
    std::unique_ptr<int> p(new int(3));
    move_on_copy_wrapper<std::unique_ptr<int>> mp(std::move(p));

    [mp]()
    {
        std::cout<<"*mp.value="<<*mp.value<<std::endl;
    }
    ();

    std::cout<<"p="<<p.get()<<", mp="<<mp.value.get()<<std::endl;
}

Dein Versuch 2 wird fast funktionieren.

Was fehlt, ist, dass Sie Ihren bind nicht aufgefordert haben, einen Parameter zu erwarten:

std::for_each(arr.begin(), arr.end(),
   std::bind([](const unique_ptr<int>& p, int& i){
      i += (*p);
   }, std::move(p), std::placeholders::_1)
);

Der placeholders::_1 ist notwendig, um dem Ergebnis von bind mitzuteilen bind dass es einen Parameter erwartet, der für seinen operator() .

Dies ist auch der Vorschlag, der hier in @ marton78s Antwort gegeben wird.







c++11