Выражение должно иметь константное значение visual studio

Обновлено: 25.06.2024

Вы найдете много констант в самом framework, в классе Math, где определена константа для PI.

Но, конечно, самое интересное-объявить собственные константы. Константу можно определить в области видимости метода, например:

Однако большинство констант объявляются на уровне класса, так что они могут быть доступны (но не изменены, конечно) из всех методов класса и даже вне класса, в зависимости от области видимости. Константа будет действовать как статический член класса, что означает, что вы можете получить к ней доступ без создания экземпляра класса. Имея это в виду, давайте попробуем полный пример, где определены две константы - личная и публичная константы:

Обратите внимание, как я определяю класс (SomeClass) с двумя константами. Первый является частным, поэтому он может быть доступен только из самого класса, но другой общедоступный. Итак, в нашем основном программном коде я обращаюсь к обеим константам по-разному - во-первых, напрямую, так как неправильный ответ общедоступен, а во-вторых, с помощью метода GetAnswer ().

Какой тип данных может быть задан как константа?

Так как константы должны быть объявлены сразу и не могут быть изменены позже, значение, которое вы назначаете константе, должно быть константным выражением, и компилятор должен быть в состоянии оценить значение уже во время компиляции. Это означает, что числа, логические значения и строки могут быть использованы для константы, в то время как, например, объект DateTime не может быть использован в качестве константы.

Поскольку компилятор должен знать значение немедленно, это также означает, что существуют некоторые ограничения на то, что можно сделать при установке значения. Например, это прекрасные примеры того, что вы можете сделать:

С другой стороны, нельзя использовать результат вызова метода или непостоянный член класса, так как они не являются константными выражениями. Вот несколько примеров того, что вы не можете сделать:

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

Альтернатива константе: поле readonly

Если вы ищете несколько менее ограничительную версию константы класса, вы можете взглянуть на ключевое слово readonly. Он недоступен на уровне метода, но может использоваться на уровне класса для определения поля, которое может быть изменено только во время объявления или выполнения метода конструктора класса. Таким образом, как только объект будет доступен для использования, поле readonly будет иметь одно и то же значение навсегда и не может быть изменено пользователем. Давайте попробуем:

Итак, у нас есть два поля только для чтения: первое-частное, второе-публичное (обычно у нас есть свойства для этого, но немного потерпите меня). Первый объявляется без значения (это можно сделать с полями только для чтения, в отличие от констант), а второй инициализируется немедленно. Вы также заметите, что мы используем класс DateTime в качестве типа данных и присваиваем ему непостоянное значение. Другими словами, мы делаем много вещей, которые мы не можем сделать с константами, делая поля только для чтения хорошей альтернативой константам.

Обратите внимание, как я присваиваю значение полю rightNow в конструкторе класса SomeClass. Как уже упоминалось, это последний шанс присвоить значение полю только для чтения. После этого, независимо от того, находитесь ли вы в методе внутри определяющего класса или снаружи, вы получите ошибку компиляции, если попытаетесь присвоить значение полю только для чтения.

Резюме

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

Почему я получаю эту ошибку:

выражение должно иметь постоянное значение.

ОТВЕТЫ

Ответ 1

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

Если вы хотите фиксированный размер, тогда они должны быть объявлены как const:

даже не предоставляет имя переменной.

Ответ 2

С++ не позволяет использовать непостоянные значения для размера массива. Это так, как оно было разработано.

C99 позволяет размеру массива быть переменной, но я не уверен, что это разрешено для двух измерений. Некоторые компиляторы С++ (gcc) разрешают это как расширение, но вам может потребоваться включить параметр компилятора, чтобы разрешить его.

И я почти пропустил это - вам нужно объявить имя переменной, а не только размеры массива.

Ответ 3

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

UPD: некоторые компиляторы фактически позволят вам снять это. IIRC, g++ имеет эту функцию. Однако никогда не используйте его, потому что ваш код станет не переносимым для компиляторов.

Ответ 4

Ответ 5

Когда вы объявляете переменную как здесь

вы сообщаете компилятору С++, что во время выполнения вы хотите, чтобы 100 последовательных целых чисел были выделены в программную память. Затем компилятор предоставит вашей программе доступ к такой большой памяти, и все будет хорошо с миром.

Если вы скажете компилятору

у компилятора нет возможности узнать, сколько памяти вам действительно понадобится во время выполнения, не делая много очень сложного анализа, чтобы отслеживать каждое последнее место, где значения x и y изменены [если есть]. Вместо поддержки таких массивов с переменными размерами С++ и C настоятельно рекомендуют, если вы не хотите, чтобы вы использовали malloc(), чтобы вручную выделить нужное пространство.

TL; DR

a теперь представляет собой 2D массив размером 5x5 и будет вести себя так же, как int a [5] [5]. Поскольку вы вручную выделили память, С++ и C требуют, чтобы вы удалили ее вручную.

Ответ 6

Нет, он не обязательно должен быть постоянным, причина, почему его код выше неправильный, заключается в том, что ему нужно включить имя переменной перед объявлением.

я столкнулся с ситуацией, когда не-void метод отсутствует возвращение заявление и код все еще компилируется. Я знаю, что операторы после цикла while являются недоступен(мертвый код) и никогда не будут казнены. Но почему компилятор даже не предупреждает о возврате чего-то? Или почему язык позволяет нам иметь непустой метод, имеющий бесконечный цикл и ничего не возвращающий?

Если я добавлю перерыв оператор (даже условный) в цикле while компилятор жалуется на печально известные ошибки: "метод не возвращает значение" (Eclipse) и "не все пути кода возвращают значение" (Visual Studio)

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

правило для непустых методов -каждый возвращаемый путь кода должен возвращать значение, и это правило выполняется в вашей программе: ноль из нулевых путей кода, которые возвращают, возвращают значение. Правило не является "каждый метод Non-void должен иметь путь кода, который возвращает".

это позволяет писать заглушки-методы например:

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

что ваш метод имеет недостижимую конечную точку из-за goto (помните, a while(true) - это просто более приятный способ писать goto ) вместо throw (что является еще одной формой goto ) не относится.

почему разве компилятор даже не предупреждает о возврате чего-то?

потому что у компилятора нет хороших доказательств того, что код неверен. Кто-то написал while(true) и кажется вероятным, что человек, который это сделал, знал, что делает.

см. мои статьи на эту тему, здесь:

Java-компилятор достаточно умен, чтобы найти недостижимый код ( код после while loop)

С недоступен, нет смысла в добавляем return заявление (после while заканчивается)

то же самое с условным if

так как логическое условие someBoolean можно оценить только либо true или false , нет необходимости предоставлять return явно после if-else , потому что этот код недоступен, и Java не жалуется на это.

компилятор знает, что while цикл никогда не прекратит выполнение, следовательно, метод никогда не завершится, следовательно, return оператор не требуется.

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

Если вы используете переменную - компилятор будет применять правило:

это не будет компилироваться:

спецификация Java определяет концепцию под названием Unreachable statements . Вам не разрешено иметь недостижимый оператор в коде (это ошибка времени компиляции). Вам даже не разрешено иметь оператор return после while (true); оператор в Java. А while(true); оператор делает следующие операторы недоступными по определению, поэтому вам не нужен return заявление.

обратите внимание, что в то время как проблема останова неразрешимо в общем случае, определение Недостижимое утверждение более строго, чем просто остановка. Это решение очень конкретных случаев, когда программа определенно не останавливается. Теоретически компилятор не может обнаружить все бесконечные циклы и недостижимые операторы, но он должен обнаружить конкретные случаи, определенные в спецификации (например, while(true) случае)

компилятор достаточно умен, чтобы узнать, что ваш while цикл бесконечен.

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

Итак, чтобы ответить на ваш вопрос:

компилятор анализирует ваш код и после выяснения того, что ни один путь выполнения не приводит к падению конца функция заканчивается хорошо.

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

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

в теории типов есть что-то, называемое снизу тип который является подклассом любого другого типа (!) и используется для указания на прекращение, среди прочего. (Исключения могут считаться типом non-termination-вы не завершаете работу по обычному пути.)

таким образом, с теоретической точки зрения, эти утверждения, которые не заканчиваются, можно считать возвращающими что - то типа Bottom, который является подтипом int, поэтому вы (вроде) получаете свое возвращение значение в конце концов с точки зрения типа. И совершенно нормально, что не имеет никакого смысла, что один тип может быть подклассом всего остального, включая int, потому что вы никогда не возвращаете его.

в любом случае, с помощью явной теории типов или нет, компиляторы (авторы компиляторов) признают, что запрашивать возвращаемое значение после неокончаемого оператора глупо: нет возможного случая, в котором вам могло бы понадобиться это значение. (Может быть приятно, чтобы ваш компилятор предупреждал вас, когда он знает, что что-то не закончится, но похоже, вы хотите, чтобы он что-то вернул. Но это лучше оставить для style-checkers a la lint, так как, возможно, вам нужна подпись типа таким образом по какой-то другой причине (например, подклассы), но вы действительно хотите non-termination.)

Visual studio имеет интеллектуальный движок для обнаружения, если вы ввели тип возврата, то он должен иметь оператор return с функцией / методом.

Как и в PHP, ваш тип возврата true, если вы ничего не вернули. компилятор получает 1, если ничего не вернулось.

компилятор знает, что в то время как сам оператор имеет бесконечную природу, поэтому не рассматривать его. и компилятор php автоматически получит true, если вы напишете условие в выражение while.

но не в случае VS он вернет вам ошибку в стеке .

ваш цикл while будет работать вечно и, следовательно, не выйдет наружу, пока; он будет продолжать выполняться. Следовательно, внешняя часть while<> недоступна, и нет смысла писать return или нет. Компилятор достаточно умен, чтобы выяснить, какая часть достижима, а какая нет.

приведенный выше код не будет компилироваться, потому что может быть случай, когда значение переменной x изменяется внутри тела цикла while. Так это делает внешняя часть цикла while добраться! И, следовательно, компилятор выдаст ошибку "не найден оператор return".

компилятор недостаточно умен (или, скорее, ленив;)), чтобы выяснить, будет ли изменено значение x или нет. Надеюсь, это все прояснит.

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

этот код действителен и на всех других языках (возможно, кроме Haskell!). Потому что первое предположение-мы "намеренно" пишем какой-то код.

и есть ситуации, когда этот код может быть полностью действительным, например, если вы собираетесь использовать его в качестве потока; или если он возвращал Task<int> , вы можете сделать некоторую проверку ошибок на основе возвращенного значения int-которое не должно быть возвращено.

в частности, правила заключаются в том, что метод с возвращаемым типом не должен иметь возможности вполне нормально и должен вместо этого всегда завершать резко (резко здесь, указывая через оператор возврата или исключение) per JLS 8.4.7.

если объявлен метод с возвращаемым типом, то время компиляции ошибка возникает, если тело метода может завершиться нормально. Другими словами, метод с типом return должен возвращать только с помощью оператор return, который предоставляет значение return;не допускается "опустите конец его тела".

компилятор смотрит, есть ли нормальное завершение можно на основе правил, определенных в JLS 14.21 Недостижимые Утверждения а также определяет правила для нормального завершения работы.

Примечательно, что правила для недостижимых операторов делают особый случай только для циклов, которые имеют определенный true константное выражение:

  • пока оператор достижим, и выражение условия не является константным выражением (§15.28) с значение true.

  • существует оператор reachable break, который выходит из оператора while.

так если while заявление вполне нормально, то оператор возврата ниже необходимо, так как код считается достижимым, и любой while цикл без достижимого оператора break или константы true выражение считается способным нормально завершаться.

эти правила означают, что ваш while заявление с постоянным истинным выражением и без break is никогда не считалось завершить нормально, и поэтому любой код ниже никогда не считалось достижимым. Конец метода находится ниже цикла, и поскольку все ниже цикла недоступно, то и конец метода, и, следовательно, метод не может быть вполне нормально (который является то, что компилятор ищет).

if заявления на с другой стороны, не имеют специального исключения в отношении постоянных выражений, которые предоставляются циклам.

причина различия довольно интересна и связана с желанием разрешить условные флаги компиляции, которые не вызывают ошибок компилятора (из JLS):

  • оператор if-then может нормально завершить iff по крайней мере один из верно следующее:

    • оператор if-then достижим, а выражение условия-нет постоянное выражение, значение которого равно true.

    • then-statement может завершаться нормально.

    • оператор then достижим, если оператор if-then-else достижим, и выражение условия не является константным выражением значение которого false.

    • оператор else - достижимый, если оператор if-then-else достижим, и выражение условия не является константным выражением значением которого является True.

    почему условный разрыв оператор приводит к ошибке компилятора?

    как указано в правилах достижимости цикла, цикл while также может завершаться нормально, если он содержит оператор reachable break. Поскольку правила для достижимости if заявление затем предложение не принимает условие if в соображение вообще, такое условное if заявление затем предложение всегда считается достижимым.

    если break is достижимый, то код после цикла еще раз также считается достижимым. Поскольку нет достижимого кода, который приводит к крутой завершение после цикла метод считается способным завершить нормально, и поэтому компилятор помечает его как ошибку.

    Для того, чтобы функция использовалась в константном выражении, то есть, вычислялась компилятором, необходимо определить её со спецификатором constexpr .

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

    const

    Объекты со спецификатором const не могут быть изменены, а также должны быть инициализированы.

    Поскольку объекты со спецификаторов const не могут быть изменены, то следующий код будет ошибочным:

    Обратите внимание, что const изменяет тип объекта, а не указание того, как должна быть назначена переменная. const ограничивает способы работы с объектом.

    При использовании указателя задействуются два объекта: сам указатель и объект, на который указывает. Префиксное' объявление указателя с const делает константным объект, а не указатель. Чтобы объявить как const сам указатель, а не объект, на который он указывает, необходимо поместить const после символа указателя. Например:

    Местоположение const относительно базового типа не принципиально, поскольку не существует типа данных const*. Принципиальным является положение const относительно символа *. Поэтому возможны следующие записи:

    Объект, который является константой при доступе через один указатель, может быть изменяемым при доступе иными способами. Это особенно полезно для аргументов функции. Объявляя аргумент указателя как const , функции запрещается изменять объект, на который указывает. Например:

    Первая версия используется для строк, элементы которых не должны быть изменены функцией и возвращает указатель на const, который не позволяет изменять результат. Вторая версия используется для изменяемых строк.

    Вы можете назначить адрес неконстантной переменной указателю на константу, потому что это не может нанести никакого вреда. Однако адрес константы нельзя назначить неконстантному указателю, поскольку это позволит изменить значение объекта. Например:

    constexpr

    Константное выражение является выражением, которое вычисляется во время компиляции. Константные выражения не могут использовать значения и переменные, которые не известны во время компиляции.

    Существует множество причин, по которым кому-то может понадобиться именованная константа, а не буква или значение, хранящееся в переменной:

    1. Именованные константы упрощают понимание и поддержку кода.
    2. Переменная может быть изменена (поэтому мы должны быть более осторожными в наших рассуждениях, чем для константы).
    3. Язык требует постоянных выражений для размеров массивов, меток case и аргументов значений шаблона.
    4. Программисты встраиваемых систем любят помещать неизменяемые данные в постоянное запоминающее устройство. Потому что доступная только для чтения память дешевле, чем динамическая память (с точки зрения затрат и потребления энергии) и часто более многочисленная. Кроме того, данные в постоянной памяти защищены от большинства сбоев системы.
    5. Если инициализация выполняется во время компиляции, то в многопоточной программе системе не может быть никаких расхождений данных.
    6. Выполнение вычислений на этапе компиляции улучшает производительность программы.

    Значение constexpr вычисляется во время выполнения компиляции, и если оно не может быть вычислено, то компилятор выдаст ошибку.

    Возможности константных выражений достаточно велики, поскольку имеется возможность использовать целочисленнные типы данных, данные с плавающей точкой, перечисления, а также операторы, которые не изменяют значения переменных (такие как +, ? и [] , но не = или ++ )

    Читайте также: