Я изучил некоторые из новых функций 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
и так далее) и предоставляют в основном дублирующие функции?
Вам нужно знать размер вашей строки, и единственный способ добиться этого — использовать пакет параметров 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
и некоторые арифметические операции.
Благодаря Ответ Морвенн Я придумал полное решение для пользовательских двоичных литералов для тех из нас, кто застрял в 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);
}