Возможно ли инициализировать массив символов условно выбранным строковым литералом?
Я знаю, что вполне возможно инициализировать массив char
строковым литералом:
char arr[] = "foo";
С++ 11 8.5.2/1 говорит так:
A char
(будь то обычный массив char
, signed char
или unsigned char
), char16_t
, массив char32_t
или wchar_t
массив может быть инициализирован узким символьным литералом, char16_t
строковый литерал, строка char32_t
литерального или широкого строкового литерала, соответственно, или соответствующим образом напечатанным строковым литералом, заключенным в фигурные скобки. Последовательные символы значения строкового литерала инициализируют элементы массива....
Однако, можете ли вы сделать то же самое с двумя строковыми литералами в условном выражении? Например, например:
char arr[] = MY_BOOLEAN_MACRO() ? "foo" : "bar";
(Где MY_BOOLEAN_MACRO()
расширяется до a 1
или 0
).
Соответствующие части С++ 11 5.16 (Условный оператор) следующие:
1... Первое выражение преобразуется контекстом в bool
(раздел 4). Он оценивается, и если он true
, результатом условного выражения является значение второго выражения, в противном случае третьего выражения....
4 Если второй и третий операнды являются glvalues одной и той же категории значений и имеют один и тот же тип, результат относится к типу и категории значений, и это бит-поле, если второй или третий операнд является битовым полем, или если оба являются битовыми полями.
Обратите внимание, что литералы имеют одинаковую длину и, следовательно, они оба являются значениями типа const char[4]
.
GCC one ideone принимает конструкцию. Но, читая стандарт, я просто не уверен, законно это или нет. Кто-нибудь лучше понимает?
Ответы
Ответ 1
С другой стороны, clang
не принимает такой код (видеть его в прямом эфире), и я верю, что clang
верен на этом (MSVC также отклоняет этот код).
Строковый литерал определяется грамматикой в разделе 2.14.5
:
string-literal:
encoding-prefixopt" s-char-sequenceopt"
encoding-prefixoptR raw-string
и в первом абзаце из этого раздела говорится (основное внимание):
Строковый литерал представляет собой последовательность символов (как определено в 2.14.3) , окруженный двойными кавычками, необязательно с префиксом R, u8, u8R, u, uR, U, UR, L или LR, как в "..." , R "(...)", u8 "..." , u8R " (...)", u "..." , uR "~ (...) ~", U "..." , UR "zzz (...) zzz", L "..." , или LR "(... )", соответственно
и далее говорится, что тип узкой строковой литералы:
"массив n const char",
а также:
имеет статическую продолжительность хранения
но "массив из n const char" со статической продолжительностью хранения не является строковым литералом, так как он не соответствует грамматике и не соответствует абзацу 1
.
Мы можем сделать это сбой на gcc
, если мы используем не константное выражение (видеть его в прямом эфире):
bool x = true ;
char arr[] = x ? "foo" : "bar";
что означает, что это, вероятно, расширение, но оно не соответствует требованиям, поскольку оно не вызывает предупреждения в режиме строгого соответствия, т.е. используя -std=c++11 -pedantic
. Из раздела 1.4
[intro.compliance]:
[...] Реализации необходимы для диагностики программ, которые используют такие расширения, которые плохо сформированы в соответствии с этим Интернационалом Стандарт. Однако, сделав это, они могут компилировать и выполнять такие программы.
Ответ 2
Это работает в GCC на С++ 11 или новее, потому что литералы, которые вы предоставляете, детерминированы во время компиляции (например, они constexpr
). Поскольку компилятор может определить, какой из них истинен, можно определить, какой из них использовать.
Чтобы удалить способность constexpr
, попробуйте что-то вроде этого:
#include <iostream>
#include <cstdlib>
int main() {
bool _bool = rand();
char arr[] = (_bool) ? "asdf" : "ffff";
std::cout << arr << std::endl;
}
GCC затем с ошибками:
g++ test.cpp -std=c++11
test.cpp: In function ‘int main()’:
test.cpp:6:34: error: initializer fails to determine size of ‘arr’
char arr[] = (_bool) ? "asdf" : "ffff";
^
test.cpp:6:34: error: array must be initialized with a brace-enclosed initializer
Я не знаю стандартного текстового определения достаточно хорошо, чтобы узнать, где и почему это действительно, но я считаю, что он действителен.
Для дальнейшего чтения constexpr
и того, как это может повлиять на компилируемость, см. ответ @ShafikYaghmour в другом вопросе.