2010-04-08 3 views
2

Может кто-нибудь, пожалуйста, объясните следующую строку кода, найденного на http://docs.openttd.org/ai__cargo_8cpp_source.htmlНет пробелов между оператором трансляции и оператором пространства имен?

return (AICargo::TownEffect)::CargoSpec::Get(cargo_type)->town_effect; 

Если эта строка была:

return (AICargo::TownEffect) ::CargoSpec::Get(cargo_type)->town_effect; 

(обратите внимание на пробел между TownEffect) и ::), то я бы понял это нормально , Однако в этом документе нет пробелов *, что означает, что (AICargo::TownEffect) является левым операндом оператора ::.

Как этот код работает/компилируется? Или две вещи эквивалентны из-за какого-то неясного правила C++?

* Это то же самое в файле cpp.

ответ

8

Помимо разделения маркеров, пробел обычно не имеет существенного значения в грамматике C++.

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

(AICargo::TownEffect)::CargoSpec::Get 

и

AICargo::TownEffect::CargoSpec::Get 

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

+1

Технически, «AICargo :: TownEffect» является _type-id_, а не _qualified-id_, потому что он называет тип, а не объект или функцию. –

1

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

Это не более нечитаемым, что:

if(cargo_type){return cargo_type->town_effect;} 

Это, вероятно, связано с тем, что ( и ) не может быть частью идентификатора.

1

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

Я хочу добавить, что на C++ вы не должны использовать старые стили C-стиля как стиль. Они обычно сильнее, чем вы хотите, и отбрасывают const, что очень часто не то, что вы хотите. Кроме того, их практически невозможно найти в вашей базе кода, что затрудняет просмотр выражений, которые, как правило, гораздо чаще вызывают ошибки.

Вместо этого в этом случае, если вам действительно нужна полная мощность литья в стиле C (без учета const ness на данный момент), вы должны использовать reinterpret_cast<AICargo::TownEffect>. Однако, не глядя на код, меня не удивило бы, если бы было достаточно static_cast.

+0

Хотя следует отметить, что 'static_cast' не повышает безопасность на много, возможно, что' dynamic_cast' должен быть заменен в режиме отладки. –

+0

Напротив: для цитирования Stroustrup: «Оператор * static_cast * преобразует связанные типы, такие как один тип указателя в другой, в одну и ту же иерархию классов, перечисление целочисленного типа или тип с плавающей точкой в ​​интегральный тип. * Reinterpret_cast * обрабатывает преобразования между несвязанными типами, такими как целое число с указателем, или указатель на несвязанный тип указателя. Это различие позволяет компилятору применять минимальную проверку типов для * static_cast * и упрощает для программистов поиск более опасных конверсии, представленные как * reinterpret_cast * s. " – jemfinch

+5

@Matthieu M .: 'dynamic_cast' и' static_cast' делают совершенно разные вещи. Используя их взаимозаменяемо (например, в разных конфигурациях сборки), возникает проблема. Если корректная версия релиза использует 'static_cast', тогда должна быть построена отладка. Единственный раз, когда вы захотите, чтобы 'dynamic_cast' в сборке отладки, но не в сборке релиза, находился внутри assert. –

Смежные вопросы