Как получить наименьшую переменную с пользовательскими литералами C ++ 11

Я изучил некоторые из новых функций C ++ 11 и был очень впечатлен некоторыми из них, особенно пользовательскими литералами.

Это позволяет вам определять литералы вида 999_something где something контролирует, что делается с 999 генерировать буквальное. Так что больше не нужно использовать:

#define MEG * 1024 * 1024
int ten_meg = 10 M;

Я думал, что было бы неплохо использовать подчеркивания в больших количествах, как 1_000_000_blah что соответствовало бы удобочитаемости Perl, хотя идея о том, что Perl каким-то образом читается, кажется мне довольно смешной 🙂

Это также было бы удобно для двоичных значений, таких как 1101_1110_b а также 0011_0011_1100_1111_b,

Очевидно из-за _ символы, это должен быть тип raw, обрабатывающий строку C, и я согласен с этим.

Что я не может выяснить, как доставить другой тип в зависимости от размера операнда. Например:

1101_1110_b

должен дать char (при условии, char конечно 8-битный) пока:

0011_0011_1100_1111_b

поставил бы 16-битный тип.

Я могу получить длину операнда из функции буквального оператора operator"" сам по себе (путем подсчета цифр символов), но тип возвращаемого значения, похоже, зафиксирован в функции, поэтому я не могу вернуть другой тип, основанный на этом.

Можно ли это сделать с помощью одного суффикса? _b в рамках определенных пользователем типов, или мне нужно прибегнуть к разделению типов вручную (_b8, _b16 и так далее) и предоставляют в основном дублирующие функции?

9

Решение

Вам нужно знать размер вашей строки, и единственный способ добиться этого — использовать пакет параметров sizeof... на. Вы должны быть в состоянии достичь того, что вы хотите с помощью шаблона Variadic operator"":

#include <cstdint>
#include <type_traits>

template<char... String>
auto operator "" _b()
-> typename std::conditional<sizeof...(String) <= 8,
uint8_t,
typename std::conditional<sizeof...(String) <= 16,
uint16_t,
uint32_t
>::type
>::type
{
// Do whatever you want here
}

И вот тестовый пример:

int main()
{
auto a = 10000001_b;
auto b = 100000001_b;

std::cout << std::boolalpha;
std::cout << std::is_same<decltype(a), uint8_t>::value << "\n"; // true
std::cout << std::is_same<decltype(b), uint16_t>::value << "\n"; // true
}

К сожалению, это решение не может обрабатывать разделитель цифр. Кроме того, std::conditional машинка довольно некрасивая. Возможно, вы могли бы работать что-то лучше с boost::mpl::vector, boost::mpl::at и некоторые арифметические операции.

6

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

Благодаря Ответ Морвенн Я придумал полное решение для пользовательских двоичных литералов для тех из нас, кто застрял в C ++ 11:

#include <cstdint>
#include <type_traits>

/// User-defined binary literal for C++11
/// @see https://stackoverflow.com/a/538101 / https://gist.github.com/lichray/4153963
/// @see https://stackoverflow.com/a/17229703
namespace detail {

template<class tValueType, char... digits>
struct binary_literal;

template<char... digits>
struct unsigned_binary_literal
{
using Type = typename std::conditional<sizeof...(digits) <= 8, uint8_t,
typename std::conditional<sizeof...(digits) <= 16, uint16_t,
typename std::conditional<sizeof...(digits) <= 32, uint32_t, uint64_t>::type
>::type
>::type;
};

template<char... digits>
struct signed_binary_literal
{
using Type = typename std::conditional<sizeof...(digits) <= 8, int8_t,
typename std::conditional<sizeof...(digits) <= 16, int16_t,
typename std::conditional<sizeof...(digits) <= 32, int32_t, int64_t>::type
>::type
>::type;
};

template<class tValueType, char high, char... digits>
struct binary_literal<tValueType, high, digits...>
{
static constexpr tValueType value = (static_cast<tValueType>(high == '1') << (sizeof...(digits))) ^ binary_literal<tValueType, digits...>::value;
};

template<class tValueType, char high>
struct binary_literal<tValueType, high>
{
static constexpr tValueType value = (high == '1');
};
} // namespace detail

/// C++11 support for binary literal
/// @tparam digits to transform to an unsigned integer
template<char... digits>
constexpr auto operator "" _bin() -> typename detail::unsigned_binary_literal<digits...>::Type
{
return detail::binary_literal<typename detail::unsigned_binary_literal<digits...>::Type, digits...>::value;
}

/// C++11 support for binary literal
/// @tparam digits to transform to a signed integer
template<char... digits>
constexpr auto operator "" _sbin() -> typename detail::signed_binary_literal<digits...>::Type
{
return static_cast<typename detail::signed_binary_literal<digits...>::Type>(detail::binary_literal<typename detail::unsigned_binary_literal<digits...>::Type, digits...>::value);
}
0

По вопросам рекламы [email protected]