Разница между перехваченными и неявно перехваченными переменными constexpr в лямбда-выражениях - PullRequest
0 голосов
/ 09 мая 2018

Этот вопрос Доступ к переменной constexpr внутри лямбда-выражения без захвата ответил, почему повторный захват в приведенном ниже примере не является строго необходимым.Но, с другой стороны, возникает ошибка, если она захвачена.

Ошибка, кажется, вызвана рекурсивной природой foo().

template<typename T>
constexpr int bar(const T& x) { // NOK
//constexpr int bar(T x) { // OK
    return x;
}

template<typename T>
int foo(const T& l) {
    constexpr auto x = l() - 1;
    auto y = [&]{return bar(x);}; // if ref-capture is used, the above bar(const T&) is NOK, why? 

    if constexpr(x <= 0) {
        return 42;
    }
    else {
        return foo(y);
    }
}

auto l2 = []{
    return 3;
};

int main() {
    foo(l2);
}

1 Ответ

0 голосов
/ 09 мая 2018

Если мы используем clang в качестве компилятора, который обычно более актуален, чем gcc, когда речь идет о юристе по языку, мы обнаруживаем, что упрощенный пример очень показателен:

template<typename T>
int foo(T/*&*/ l) {
    constexpr auto x = l() - 1;

    if constexpr(x <= 0) {
        return 42;
    }
    else {
        return 0;
    }
}

auto l2 = []{
    return 3;
};

int main() {
    foo(l2);
}

Добавление и удаление ссылки в foo() подписи делает программу скомпилированной или некомпилированной. Я полагаю, что это имеет отношение к пункту 12 на тему константного выражения на cppreference:

id-выражение, ссылающееся на переменную или член данных ссылочный тип , если только он не был инициализирован константным выражением или его время жизни не началось в рамках оценки этого выражения

https://en.cppreference.com/w/cpp/language/constant_expression

Таким образом, оба эти утверждения, по-видимому, не удовлетворены, поскольку ссылка не была инициализирована с помощью константного выражения, и ее время жизни не началось с оценки выражения.

...