Проверка преобразования типа времени компиляции (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.

7

Решение

Самостоятельный ответ:
Я нашел полное решение, вдохновленное комментариями и другими ответами на мой вопрос и другими вопросами, такими как https://stackoverflow.com/a/13384317/1149664.

Решение состоит в том, чтобы использовать шаблонную форму пользовательских литералов и суммировать число вручную, умножая сумму на основе уже проанализированных цифр на 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;
};
4

Другие решения

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

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

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


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

3

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

1
А ты уже прошел курс программирования? Супер скидка!
Прокачать скилл $$$
×