Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

These allow you to define literals of the form 999_something where something controls what is done to the 999 to generate the literal. 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 :-)

It would also be handy for binary values like 1101_1110_b and 0011_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.

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:

0011_0011_1100_1111_b

would deliver a 16-bit type.

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.

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?

like image 508
paxdiablo Avatar asked Jun 21 '13 04:06

paxdiablo


People also ask

How do you define a literal in C++?

Literals are data used for representing fixed values. They can be used directly in the code. For example: 1 , 2.5 , 'c' etc. Here, 1 , 2.5 and 'c' are literals.

How do you write short in C++?

For example, // small integer short a = 12345; Here, a is a short integer variable. Note: short is equivalent to short int .

Which operators are not used with literals?

All the operators above except _r and _t are cooked literals.

What is difference between constants and literals?

Constants are variables that can't vary, whereas Literals are literally numbers/letters that indicate the value of a variable or constant.


1 Answers

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. You should be able to achieve what you want with a variadic template 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. You could probably work something better with boost::mpl::vector, boost::mpl::at and some arithmetic operations.

like image 107
Morwenn Avatar answered Sep 28 '22 03:09

Morwenn