В GCC внутри лямбды я могу получить переменную constexpr из лямбды шаблона, отличного от constexpr, но не в Visual C++

Этот код нормально компилируется в gcc, но не работает в Visual C++.

MCVE = https://godbolt.org/z/K7d5PEs65

int main(){
      int localVariable=0; //some local variable
      auto lamb=[&]<int s>() {
          if constexpr(s==5){localVariable=7;}
          ///^ may modify some local variables
          return 8;
      };
      constexpr int gOk=lamb.operator()<2>();
      [&]<int s2>() {
          ///vvv can edit only here
          constexpr int gFail=lamb.operator()<s2>();
          ///^^^ can edit only here
      }.operator()<2>();
}

Выражение ошибки C2131 не получило константу

Мне нужно, чтобы gFail была переменной constexpr, а lamb иногда создавало побочный эффект во время выполнения, в зависимости от значения переменной шаблона s.

Пожалуйста, дайте ссылку и обходной путь для случая Visual C++.

Обновлено: Кстати, причина, по которой я смешиваю constexpr и не-constexpr внутри одного и того же lamb, заключается в том, чтобы сделать вызов удобным. По задумке пользователя, он должен заранее знать, является ли экземпляр функции lamb constexpr или нет.

Можно даже упростить Демо

Jarod42 12.07.2024 15:46

Даже не нужно вызывать вторую лямбду. И захват lamb по значению ничему не помогает. В ошибке говорится, что «сбой был вызван чтением переменной за пределами ее срока службы», но я не понимаю, о какой переменной может идти речь. Для меня это похоже на ошибку.

Igor Tandetnik 12.07.2024 15:57

Ах. Само создание lambconstexprпомогает на упрощенном примере; но не оригинал: «сбой был вызван взятием адреса объекта, не имеющего статического срока хранения». Похоже, здесь нет никакого способа победить: если lamb есть constexp, он не может изменять локальную переменную, а если это не constexpr, его нельзя использовать для инициализации переменной constexpr.

Igor Tandetnik 12.07.2024 15:59

Мне пришлось бороться с той же проблемой «чтения переменной за пределами ее жизни» в MSVC. Я думаю это ошибка/недостаток компилятора.

CygnusX1 16.07.2024 23:16
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
4
120
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я считаю, что проблема, с которой вы столкнулись, связана с ошибкой/недостатком MSVC, но я бы позволил языковым юристам указать точные причины (или опровержение моего утверждения). Обычно в таких ситуациях я упаковываю значение constexpr в целочисленную константу. Это то, что MSVC может пережевать:

#include <iostream>
#include <cstdlib>
int main(){
      int localVariable=0; //some local variable
      auto lamb=[&]<int s>() {
          if constexpr(s==5){localVariable=7;}
          return std::integral_constant<int, 8>{};
      };
      constexpr int gOk=lamb.operator()<2>().value;
      [&]<int s2>() {
          auto tmp = lamb.operator()<s2>();
          constexpr int gFail=tmp; //tmp implicitly casted from integral_constant to int.
      }.operator()<2>();
}

tmp необходимо явно указать для MSVC. Если вы назначите непосредственно gFail, вы получите то же самое «не оценивать константу».

К сожалению, это не соответствует вашему руководству «можно редактировать только здесь».


Обновление: я обеспокоен тем, что то, что вы делаете, на самом деле не будет работать ни в одном компиляторе. Если вы попытаетесь использовать 5 в качестве аргумента шаблона, вы действительно получите ошибку во всех трех компиляторах:

#include <iostream>
#include <cstdlib>
int main(){
      int localVariable=0; //some local variable
      auto lamb=[&]<int s>() {
          if constexpr(s==5){localVariable=7;} //error
          ///^ may modify some local variables
          return 8;
      };
      constexpr int gOk=lamb.operator()<5>();
      std::cout << localVariable;
}

gcc дает:

<source>: In function 'int main()':
<source>:12:43:   in 'constexpr' expansion of 'lamb.main()::<lambda()>()'
<source>:8:43: error: the value of 'lamb' is not usable in a constant expression
    8 |           if constexpr(s==5){localVariable=7;}
      |                              ~~~~~~~~~~~~~^~
<source>:7:12: note: 'lamb' was not declared 'constexpr'
    7 |       auto lamb=[&]<int s>() {
      |            ^~~~
Compiler returned: 1

Спасибо за первую часть. Это интересное открытие. Это может быть полезно или очень полезно. ....... Вторая часть :: По моему замыслу, вторая часть с <5> (таким образом, изменяя переменную во время выполнения) должна завершиться неудачей. Все в порядке.

cppBeginner 17.07.2024 02:50

Откуда вы узнали этот правильный ответ? Кажется, так сложно угадать.

cppBeginner 18.07.2024 09:15

Как я уже говорил в другом комментарии, я боролся с MSVC из-за чего-то подобного с тем же сообщением об ошибке.

CygnusX1 18.07.2024 17:30

Другие вопросы по теме