Это верно, потому что выражению constexpr
разрешено принимать значение "glvalue литерального типа, которое относится к энергонезависимому объекту, определенному с помощью constexpr, или которое относится к подобъекту такого объекта "(§5.19 / 2):
constexpr char str[] = "hello, world";
constexpr char e = str[1];
Однако может показаться, что строковые литералы не подходят под это описание:
constexpr char e = "hello, world"[1]; // error: literal is not constexpr
2.14.5 / 8 описывает тип строковых литералов:
Обычные строковые литералы и строковые литералы UTF-8 также упоминаются как узкие строковые литералы. Узкий строковый литерал имеет тип «массив из n const char», где n - размер строки, как определено ниже, и имеет статическую продолжительность хранения.
Казалось бы, объект этого типа мог бы быть проиндексирован, если бы он был временным и не имел статической длительности хранения (5.19 / 2, сразу после приведенного выше фрагмента):
[constexpr
разрешает преобразование lvalue в rvalue из]… glvalue литерального типа, который относится к энергонезависимому временному объекту, время жизни которого не закончилось, инициализируется постоянным выражением
Это особенно странно, поскольку получение значения временного объекта обычно является "обманом". Я предполагаю, что это правило применяется к аргументам функций ссылочного типа, например, в
constexpr char get_1( char const (&str)[ 6 ] )
{ return str[ 1 ]; }
constexpr char i = get_1( { 'y', 'i', 'k', 'e', 's', '\0' } ); // OK
constexpr char e = get_1( "hello" ); // error: string literal not temporary
Для чего бы то ни было, GCC 4.7 принимает get_1( "hello" )
, но отклоняет "hello"[1]
, потому что «значение '._0' нельзя использовать в константном выражении»… пока "hello"[1]
является приемлемым в качестве метки регистра или границы массива.
Здесь я ломаю несколько стандартных волосков ... Правильно ли проведен анализ, и было ли какое-то намерение для разработки этой функции?
РЕДАКТИРОВАТЬ: О ... есть некоторые мотивы для этого. Кажется, что такого рода выражения - единственный способ использовать таблицу поиска в препроцессоре. Например, это вводит блок кода, который игнорируется, если SOME_INTEGER_FLAG
не равен 1 или 5, и вызывает диагностику, если больше 6:
#if "\0\1\0\0\0\1"[ SOME_INTEGER_FLAG ]
Эта конструкция была бы новой для C ++ 11.