Разрешены ли пользовательские литералы во время компиляции или во время выполнения?
Интересно, потому что предопределенные литералы, такие как ULL
, f
и т. д. явно разрешаются во время компиляции. Стандарт (2.14.8 [lex.ext]), похоже, не определяет это, но, похоже, стремится к времени выполнения:
[2.14.8 / 2]
Пользовательский литерал обрабатывается как вызов литерального оператора или шаблона литерального оператора (13.5.8). Чтобы определить форму этого вызова для заданного пользователем литерала L с ud-суффиксом X, в контексте L ищется литеральный оператор-идентификатор с буквенным идентификатором суффикса X, используя правила для поиска без определения имени (3.4.1). Пусть S будет набором объявлений, найденных этим поиском. S не должно быть пустым.
(выделение мое.)
Однако мне кажется, что это приводит к ненужным накладным расходам времени выполнения, поскольку литералы могут добавляться только к значениям, которые доступны во время компиляции в любом случае, например 13.37f
или же "hello"_x
(где _x
является пользовательским литералом).
Затем мы получили шаблонный пользовательский литерал, который никогда не будет определен в стандарте AFAICS (т. Е. Пример не приводится, пожалуйста, докажите, что я не прав). Эта функция каким-то волшебным образом вызывается во время компиляции или все еще во время выполнения?
2 ответа
Да, вы получаете вызов функции. Но вызовы функций могут быть скомпилированы в постоянные выражения времени из-за constexpr
буквальные операторные функции.
Для примера, посмотрите этот. В качестве другого примера, чтобы показать расширенную форму constexpr
вычисления, разрешенные FDIS, чтобы иметь литералы времени компиляции base-26, которые вы можете сделать
typedef unsigned long long ull;
constexpr ull base26(char const *s, ull ps) {
return (*s && !(*s >= 'a' && *s <= 'z')) ? throw "bad char!" :
(!*s ? ps : base26(s + 1, (ps * 26ULL) + (*s - 'a')));
}
constexpr ull operator "" _26(char const *s, std::size_t len) {
return base26(s, 0);
}
поговорка "bcd-"_26
будет вычислять выражение-бросок, и, таким образом, возвращаемое значение станет непостоянным. В свою очередь, это вызывает любое использование "bcd-"_26
как постоянное выражение, чтобы стать плохо сформированным, и любое непостоянное использование, чтобы бросить во время выполнения. Разрешенная форма "bcd"_26
вычисляет постоянное выражение соответствующего вычисленного значения.
Обратите внимание, что чтение из строковых литералов явно не разрешено FDIS, однако это не представляет проблемы, и GCC поддерживает это (ссылка на символ lvalue является константным выражением, а значение символа известно во время компиляции). ИМО, если один щуриться, можно читать FDIS, как будто это разрешено делать.
Затем мы получили шаблонный пользовательский литерал, который никогда не будет определен в стандарте AFAICS (т. Е. Пример не приводится, пожалуйста, докажите, что я не прав)
Обработка литералов как вызова шаблонов литеральных операторов определена в 2.14.8. На 13.5.8 вы найдете больше примеров, подробно описывающих шаблоны функций / функций литерального оператора.
Эта функция каким-то волшебным образом вызывается во время компиляции или все еще во время выполнения?
Ключевое слово - подстановка вызова функции. Смотри 7.1.5.
@Johannes S, конечно, правильно, но я бы хотел добавить однозначно (поскольку я с этим сталкивался), что даже для constexpr
Определяемые пользователем литералы, параметры не считаются constexpr или постоянной времени компиляции, например, в том смысле, что их нельзя использовать в качестве целочисленных констант для шаблонов.
Кроме того, только такие вещи будут давать оценку во время компиляции:
inline constexpr long long _xx(unsigned long long v) {
return (v > 100 ) ? throw std::exception() : v;
}
constexpr auto a= 150_xx;
Итак, это не скомпилируется. Но это будет:
cout << 150_xx << endl;
И следующее не допускается:
inline constexpr long long _xx(unsigned long long v) {
return some_trait<v>::value;
}
Это раздражает, но естественно, учитывая, что (другие) функции constexpr могут быть вызваны также во время выполнения.
Только для целочисленных пользовательских литералов можно форсировать обработку во время компиляции, используя форму шаблона. Примеры в моем вопросе и самостоятельного ответа: /questions/47694006/proverka-preobrazovaniya-tipa-vremeni-kompilyatsii-constexpr-i-polzovatelskie-literalyi/47694030#47694030