Может ли строковый литерал быть подписан в константном выражении? - PullRequest
17 голосов
/ 15 сентября 2011

Это верно, потому что выражению 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.

Ответы [ 2 ]

6 голосов
/ 15 сентября 2011

Намерение состоит в том, что это работает, и параграфы, которые указывают, когда преобразование lvalue в rvalue является действительным, будут дополнены примечанием , в котором говорится, что lvalue, который ссылается на подобъект строкового литерала, является константный целочисленный объект, инициализированный константным выражением (которое описывается как один из разрешенных случаев) в черновике после C ++ 11.

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

1 голос
/ 17 февраля 2012

Относительно вашего вопроса о #if комитет по стандартам не намеревался увеличивать набор выражений, которые можно использовать в препроцессоре, и текущая формулировка считается дефектом.Это будет указано как основной вопрос 1436 в почтовой рассылке WG21 после Kona.Спасибо, что обратили на это наше внимание!

...