Является ли эта ссылка на ostream локальной переменной - PullRequest
0 голосов
/ 01 мая 2020

в c ++ primer 5th edition p393 написано:

Переменные, захваченные лямбда-выражением, являются локальными переменными

Затем в книге показано ostream в качестве ссылочного параметра, захваченного лямбда-ссылкой. Это похоже на:

#include <iostream>
using namespace std;
void foo(ostream &os) {
    auto f = [&os]() { os << "Hellow World !" << endl; //return os;
    };
    f();
}
void main() {
    foo(cout);
    system("pause");
}

С чем я борюсь, так это то, что здесь os не является локальной переменной для foo, она существует вне области действия foo, но может быть захвачена лямбда-выражением в то время как «Переменные, захваченные лямбда-выражением, являются локальными переменными». Что мне здесь не хватает? Кроме того, почему лямбда не может return os;? В конце концов, не является ли os объект, который существует вне лямбды и области действия foo?

Ответы [ 2 ]

3 голосов
/ 01 мая 2020

Лямбда сверху компилируется компилятором в нечто похожее на f2 в foo2 () . Таким образом, экземпляр лямбды является локальным в foo2 , а ссылка на ostream (указатель) является переменной-переменным в локальном экземпляре лямбды.

Поэтому вы должны убедиться, что лямбда с завернутой ссылкой на ostream не переживает сам ostream (os), что в данном случае не происходит, потому что лямбда-экземпляр живет только в пределах области действия функции -> меньше, чем область переданного аргумента os-ссылки ostream.

#include <iostream>
using namespace std;
void foo(ostream &os) {
    auto f = [&os]() { os << "Hellow World !" << endl; //return os;
    };
    f();
}

void foo2(ostream& os) {
    // The lambda f from foo is compiled to something similar to f2.
    struct f2 {
        f2(ostream& oss)
        : os_(oss) {}

        void operator()() const
        {
            os_ << "Hellow World !" << endl; 
        }

        private:
        ostream& os_; // Note: this is reference, but local to f2 ( == "lambda")
    };

    f2 t(os);
    t(); // call "lambda"
}

int main() {
    foo(cout);
    foo2(cout);
    return 0;
}
3 голосов
/ 01 мая 2020

С чем я борюсь, так это то, что здесь os не является локальной переменной для foo, она существует вне области действия foo,

Нет, это локально , он не существует вне foo.

объект , на который ссылается os, существует вне foo, потому что os является ссылка. Но это не имеет значения, поскольку речь идет о переменных , а не объектах .

Кроме того, почему лямбда не может return os;?

Может, вам просто нужно указать явный тип возвращаемого значения, в противном случае тип возвращаемого значения выводится как std::ostream, т. Е. Код будет пытаться скопировать поток, и он не будет -копируемый.

Но работает следующее:

auto f = [&os]() -> std::ostream& { return os << "Hellow World !" << endl; };
...