Проверка преобразования типа времени компиляции (constexpr и пользовательские литералы)

Обновление: я разместил свой собственный ответ ниже, и здесь есть более длинная версия этого вопроса: http://scrupulousabstractions.tumblr.com/post/38460349771/c-11-type-safe-use-of-integer-user-defined-literals

Вопрос:

Я сделал простой constexpr пользовательский литерал _X он получает значение в виде длинного без знака (именно так работают числовые пользовательские литералы: http://en.cppreference.com/w/cpp/language/user_literal), а затем я проверяю, чтобы значение соответствовало длинному знаку долго.

Все это работает хорошо (слишком большие значения вызывают ошибку компиляции), но только когда я явно создаю переменную, такую ​​как

constexpr auto a= 150_X;

Если вместо этого я напишу что-то типичное, как

cout << 150_X << endl;;

тесты не выполняются во время компиляции.

  • Функции constexpr выполняются только во время компиляции, если они назначены переменной constexpr? (Я не мог найти это в стандарте)

  • Можно ли добиться безопасного поведения _X что я ищу?

Полный пример:

#include<iostream>
#include<stdexcept>

inline constexpr long long testConv(unsigned long long v) {
  return (v > 100 ) ? throw std::exception() : v; 
} // will eventually use actual limit from numeric_limits

inline constexpr long long operator "" _X(unsigned long long f) { 
  return testConv(f) ;
}

int main(){
  constexpr auto a= 5_X;
  std::cout << a << std::endl;
  std::cout << 200_X << std::endl;  // This bad literal is accepted at compile time
  constexpr auto c=250_X;           // This bad literal is not accepted at compile time
  std::cout << c << std::endl;
}

о, для справки: я использовал gcc4.7.2.

3 ответа

Решение

Самостоятельный ответ: я нашел полное решение, вдохновленное комментариями и другими ответами на мой вопрос и другими вопросами, такими как /questions/33681024/ogranicheniya-gcc-c11-dlya-polzovatelskih-konstant-i-paketov-parametrov-shablona/33681043#33681043.

Решение состоит в том, чтобы использовать шаблонную форму пользовательских литералов и суммировать число вручную, умножая сумму на основе уже проанализированных цифр на 10.

Я написал подробную версию этого самостоятельного ответа здесь: http://scrupulousabstractions.tumblr.com/post/38460349771/c-11-type-safe-use-of-integer-user-defined-literals

template<char... Chars>
int operator"" _steps(){
  return {litparser<0,Chars...>::value};
}

Litparser - небольшая шаблонная метапрограмма, которая принимает список символов в качестве аргументов, расширенных из входных символов, содержащихся в пакете параметров Chars.

typedef unsigned long long ULL;

// Delcare the litparser 
template<ULL Sum, char... Chars> struct litparser;

// Specialize on the case where there's at least one character left:
template<ULL Sum, char Head, char... Rest>
struct litparser<Sum, Head, Rest...> {
// parse a digit. recurse with new sum and ramaining digits
  static const ULL value = litparser<
    (Head <'0' || Head >'9') ? throw std::exception() : 
    Sum*10 + Head-'0' , Rest...>::value;
};

// When 'Rest' finally is empty, we reach this terminating case
template<ULL Sum>  struct litparser<Sum> {
  static const ULL value = Sum;
};

constexpr функции могут быть выполнены во время компиляции; то есть они могут использоваться в константных выражениях. Если они не используются в постоянном выражении, нет смысла их выполнять во время компиляции, хотя я думаю, что это разрешено.

Поскольку вы не можете объявить параметр как constexpr (раздел 7.1.5/1) [1], я не думаю, что есть какой-либо способ форсировать оценку operator "" _X(unsigned long long) во время компиляции, но вы, вероятно, можете сделать это с template<char...> operator "" _X()

Если constexpr Функция вызывается внутри константного выражения, аргумент будет константным выражением (и если это не так, то вызов не является константным выражением). Однако нельзя заставить вызов быть константным выражением, объявив параметр constexprпотому что вы не можете объявить параметры как constexprсм. ссылку на стандарт.


[Примечание 1]: Спасибо @LightnessRacesInOrbit за поиск в стандарте для обоснования претензии в абзаце втором.

Функции Constexpr не должны выполняться во время компиляции. Но ваша цель может быть достигнута. Для лучшего понимания проблемы и примера создания итерала, который всегда оценивается во время компиляции, я рекомендую этот пост.

Другие вопросы по тегам