简体   繁体   English

如何使用C ++ 11用户定义的文字获取最小的变量

[英]How to get smallest variable with C++11 user defined literals

I've been looking into some of the new features of C++11 and am very impressed with some of them, particularly the user defined literals. 我一直在研究C ++ 11的一些新功能,并且对其中的一些非常印象深刻,特别是用户定义的文字。

These allow you to define literals of the form 999_something where something controls what is done to the 999 to generate the literal. 这些允许您定义999_something形式的文字,其中something控制对999以生成文字。 So no more having to use: 所以不必再使用:

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

I was thinking this would be nice to implement underscores in large numbers, like 1_000_000_blah which would match the readability of Perl, though the idea that Perl is somehow readable seems quite humorous to me :-) 我认为这样很好地实现大量的下划线,比如1_000_000_blah ,这与Perl的可读性相匹配,虽然Perl在某种程度上可读的想法对我来说似乎很幽默:-)

It would also be handy for binary values like 1101_1110_b and 0011_0011_1100_1111_b . 它对于像1101_1110_b0011_0011_1100_1111_b这样的二进制值也很方便。

Obviously because of the _ characters, these will need to be raw mode type, processing a C string, and I'm okay with that. 显然由于_字符,这些将需要是原始模式类型,处理C字符串,我没关系。

What I can't figure out is how to deliver a different type based on the operand size. 无法弄清楚的是如何根据操作数大小提供不同的类型。 For example: 例如:

1101_1110_b

should give a char (assuming char is 8-bit of course) while: 应该给一个char (假设char当然是8位),而:

0011_0011_1100_1111_b

would deliver a 16-bit type. 将提供16位类型。

I can get the length of the operand from within the literal operator function operator"" itself (by counting digit chars) but the return type seems to be fixed to the function so I can't return a different type based on this. 我可以从文字运算符函数operator""本身(通过计数数字字符)获取操作数的长度,但返回类型似乎是固定到函数,所以我不能基于此返回不同的类型。

Can this be done with a single suffix _b within the user defined types framework, or do I need to resort to splitting the types apart manually ( _b8 , _b16 and so on) and provide mostly duplicate functions? 可以在用户定义的类型框架中使用单个后缀_b来完成,或者我是否需要手动拆分类型( _b8_b16等)并提供大多数重复的功能?

You need to know the size oh your string, and the only way to achieve that is to have a parameter pack to use sizeof... on. 你需要知道你的字符串的大小,唯一的方法是让参数包使用sizeof... on。 You should be able to achieve what you want with a variadic template operator"" : 您应该能够通过可变参数模板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
}

And here is a test case: 这是一个测试用例:

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
}

Unfortunately, that solution can't handle the digit separator. 不幸的是,该解决方案无法处理数字分隔符。 Moreover, the std::conditional machinery is quite ugly. 而且, std::conditional机器非常难看。 You could probably work something better with boost::mpl::vector , boost::mpl::at and some arithmetic operations. 你可以用boost::mpl::vectorboost::mpl::at和一些算术运算来更好地工作。

Thanks to Morwenn's answer I came up with a full solution to user-defined binary literals for those of us stuck with C++11: 感谢Morwenn的回答,我为那些坚持使用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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM