переменная constexpr не захвачена

Dec 10 2020

Следующий код не компилируется в clang (это происходит в GCC):

struct A{
    int a;
};

auto test(){
    constexpr A x{10};
    return []{
        return x; // <-- here x is A: clang doesn't compile
    }();
}

Ошибка Clang заключается в том, что переменная 'x' не может быть неявно захвачена в лямбда- выражении без указания значения захвата по умолчанию , но я думал, что переменные constexpr захватываются всегда.

Если x - int, код компилируется:

auto test(){
    constexpr int x{10};
    return []{
        return x; // <-- here x is int: clang is ok
    }();
}

Интересно, что следующий код также компилируется:

auto test(){
    constexpr A x{10};
    return []{
        return x.a;
    }();
}

Правильно ли лязг? Если да, то в чем причина? Я использую -std = c ++ 17

--РЕДАКТИРОВАТЬ--

Следующий вопрос: могу ли я использовать значение constexpr в лямбде без его захвата? не имеет отношения к этому, так как с clang11 это больше не проблема: на самом деле, как указано выше, если x является int, clang11 компилируется.

Пример кода также присутствует в https://godbolt.org/z/rxcYjz

Ответы

2 DavisHerring Dec 25 2020 at 07:09

Когда вы return x;в первом примере, вы должны вызвать A«s конструктор копирования, который включает в себя обязывающее ссылку на xи , таким образом , УСО-использует. Можно привести аргумент, что тривиальная копия значения, используемого в константных выражениях, не должна представлять собой odr-use более чем return x.a;, но в этом правиле нет такого исключения, поэтому Clang прав, чтобы отклонить его.

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