Fun with compile-time binary literal operators

308 views
Skip to first unread message

Daniel Krügler

unread,
Nov 3, 2011, 2:12:52 PM11/3/11
to
Since gcc 4.7 has recently implemented user-defined literals, it is now
finally possible to define a binary literal operator template that
behaves very much like built-in literals. Of-course several things can
be improved here. One could support separator symbols like _ between
groups of digits, one could provide binary literals for signed values
(even though I have rarely seen uses of them), one could implement fixed
decimals, one could add overflow detection, etc...

Please enjoy - criticism is welcome as well:

#include <type_traits>
#include <cstdint>

namespace tools {
namespace details {

template<class...>
struct and_;

template<>
struct and_<> : std::true_type
{
};

template<class B1>
struct and_<B1> : B1
{
};

template<class B1, class B2>
struct and_<B1, B2> : std::conditional<B1::value, B2, B1>::type
{
};

template<class B1, class B2, class B3, class... Bn>
struct and_<B1, B2, B3, Bn...> : std::conditional<B1::value,
and_<B2, B3, Bn...>, B1
>::type
{
};

template<char...>
struct binary_to_decimal;

template<>
struct binary_to_decimal<>
{
static constexpr std::uintmax_t value = 0;
};

template<char D1, char... Dn>
struct binary_to_decimal<D1, Dn...>
{
static constexpr std::uintmax_t value =
(UINTMAX_C(1) << sizeof...(Dn)) * (D1 - '0') +
binary_to_decimal<Dn...>::value;
};

template<char D>
struct is_binary_digit : std::integral_constant<bool,
D == '0' || D == '1'
>
{
};

} // details

template <char... Digits>
constexpr std::uintmax_t operator "" _b()
{
static_assert(details::and_<details::is_binary_digit<
Digits>...>::value,
"binary digits must be 0 or 1");
return details::binary_to_decimal<Digits...>::value;
}

}

Technically it would be easily possible to prevent successful
overload-resolution the template (via sfinae means), if the digits are
not all valid, but this gave in my opinion a worse diagnostic than by
means of a static assertion.

Since gcc does currently not properly resolve using-declarations of
literal operators, you need a using directive. Here is a short example
code based on above implementation which demonstrates that the literals
are evaluated during compile-time:

using namespace tools;

static_assert(0_b == 0, "Ouch");
static_assert(1_b == 1, "Ouch");
static_assert(01_b == 1, "Ouch");
static_assert(10_b == 2, "Ouch");
static_assert(11_b == 3, "Ouch");
static_assert(00011_b == 3, "Ouch");
static_assert(1000_b == 8, "Ouch");
static_assert(1111_b == 15, "Ouch");
static_assert(101101110111000001100101110_b == 96174894, "Ouch");
static_assert(1110001100001010001001100011111101_b == 15236372733, "Ouch");

Greetings from Bremen,

Daniel Krügler


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Daniel Krügler

unread,
Nov 3, 2011, 7:48:37 PM11/3/11
to
Am 03.11.2011 19:12, schrieb Daniel Krügler:
> Since gcc does currently not properly resolve using-declarations of
> literal operators, you need a using directive.

This is just plain wrong, it works once you do it correctly ;-)

using tools::operator "" _b;

is the way to go.

For those who would like to compare the literal operator template with a raw literal operator, here is an alternative implementation:

#include <cstdint>
#include <cstddef>

namespace tools {
namespace details {

struct invalid_arg {}; // Just for simplicity, use a
// "real" std::exception in production code

constexpr std::size_t cstrlen_impl(const char* s, std::size_t i)
{
return s[i] ? cstrlen_impl(s, i + 1) : i;
}

constexpr std::size_t cstrlen(const char* s)
{
return s ? cstrlen_impl(s, 0) : throw invalid_arg{};
}

constexpr unsigned to_val(char c)
{
return (c == '0') ? 0 : (c == '1') ? 1 : throw invalid_arg{};
}

constexpr std::uintmax_t
binary_to_decimal_impl(const char* digits, std::size_t i, std::size_t n)
{
return (i != n) ? (UINTMAX_C(1) << (n - 1 - i)) * to_val(digits[i]) +
binary_to_decimal_impl(digits, i + 1, n) : 0;
}

constexpr std::uintmax_t binary_to_decimal(const char* digits)
{
return digits ?
binary_to_decimal_impl(digits, 0, cstrlen(digits))
: throw invalid_arg{};
}

}

constexpr std::uintmax_t operator "" _b(const char* digits)
{
return details::binary_to_decimal(digits);

Gennaro Prota

unread,
Nov 4, 2011, 7:43:58 PM11/4/11
to
On Thu, 03 Nov 2011 19:12:52 +0100, Daniel Krügler
<daniel....@googlemail.com> wrote:

> Since gcc 4.7 has recently implemented user-defined literals, it is now
> finally possible to define a binary literal operator template that
> behaves very much like built-in literals.

"Finally possible"? Apart from fun, what is the real-word need
for this stuff? Isn't it yet another "creative" effort on the
committee's part?

--
Gennaro Prota | name.surname gmail.com
Breeze C++ (preview): <http://sourceforge.net/projects/breeze/>
Do you need expertise in C++? I'm available.

Dave Abrahams

unread,
Nov 5, 2011, 1:10:31 AM11/5/11
to
on Fri Nov 04 2011, "Gennaro Prota" <clcppm-poster-AT-this.is.invalid> wrote:

> On Thu, 03 Nov 2011 19:12:52 +0100, Daniel Krügler
> <daniel....@googlemail.com> wrote:
>
>> Since gcc 4.7 has recently implemented user-defined literals, it is now
>> finally possible to define a binary literal operator template that
>> behaves very much like built-in literals.
>
> "Finally possible"? Apart from fun, what is the real-word need
> for this stuff?

Haven't you always wanted to write an entire lisp (or
haskell or c++ or...) compiler as a template metaprogram so you can
embed that language in your C++ code? ;-)

Everything we might do with template metaprogramming today can now have
arbitrary syntax, without the limitations imposed by C++, if you're
willing to write the programs inside user-defined literals.

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

Francis Glassborow

unread,
Nov 5, 2011, 5:17:47 PM11/5/11
to
On 05/11/2011 05:10, Dave Abrahams wrote:
> on Fri Nov 04 2011, "Gennaro Prota"<clcppm-poster-AT-this.is.invalid> wrote:
>
>> On Thu, 03 Nov 2011 19:12:52 +0100, Daniel Krügler
>> <daniel....@googlemail.com> wrote:
>>
>>> Since gcc 4.7 has recently implemented user-defined literals, it is now
>>> finally possible to define a binary literal operator template that
>>> behaves very much like built-in literals.
>>
>> "Finally possible"? Apart from fun, what is the real-word need
>> for this stuff?
>
> Haven't you always wanted to write an entire lisp (or
> haskell or c++ or...) compiler as a template metaprogram so you can
> embed that language in your C++ code? ;-)
>
> Everything we might do with template metaprogramming today can now have
> arbitrary syntax, without the limitations imposed by C++, if you're
> willing to write the programs inside user-defined literals.
>


Which reminds me of the article I wrote in the late 1990s about a
language_cast<> :) It was my column for the the April issue of .EXE
Magazine (a magazine for UK developers, that is, regrettably defunct --
it stopped publication just as it published my 100th column :) that year.

Now writing an entire C++ compiler as a metaprogram looks like an
interesting task for running on hardware circa 2020. I guess EDG should
be up to it:)


--

darkkn...@gmail.com

unread,
Nov 6, 2011, 3:45:40 AM11/6/11
to
On Fri, 4 Nov 2011 22:10:31 -0700 (PDT), Dave Abrahams
<da...@boostpro.com> wrote:

>on Fri Nov 04 2011, "Gennaro Prota" <clcppm-poster-AT-this.is.invalid> wrote:
>
>> On Thu, 03 Nov 2011 19:12:52 +0100, Daniel Krügler
>> <daniel....@googlemail.com> wrote:
>>
>>> Since gcc 4.7 has recently implemented user-defined literals, it is now
>>> finally possible to define a binary literal operator template that
>>> behaves very much like built-in literals.
>>
>> "Finally possible"? Apart from fun, what is the real-word need
>> for this stuff?
>
>Haven't you always wanted to write an entire lisp (or
>haskell or c++ or...) compiler as a template metaprogram so you can
>embed that language in your C++ code? ;-)
>
>Everything we might do with template metaprogramming today can now have
>arbitrary syntax, without the limitations imposed by C++, if you're
>willing to write the programs inside user-defined literals.

I don't know what user defined literals are but it sounds like more
obfuscated garbage which is what template meta-programming is. I've
read some of your book on template meta-programming and I find it hard
to believe that there's any real world use for such "gobbledegook". I
bet there's an easier way to solve whatever problem template
meta-programming is the solution for. Complexity costs. We need
programming techniques and tools that allow average programmers to
write understandable and maintainable software efficiently.


--

Daniel Krügler

unread,
Nov 7, 2011, 3:58:44 AM11/7/11
to
Am 05.11.2011 00:43, schrieb Gennaro Prota:
> On Thu, 03 Nov 2011 19:12:52 +0100, Daniel Krügler
> <daniel....@googlemail.com> wrote:
>
>> Since gcc 4.7 has recently implemented user-defined literals, it is now
>> finally possible to define a binary literal operator template that
>> behaves very much like built-in literals.
>
> "Finally possible"? Apart from fun, what is the real-word need
> for this stuff?

It probably depends much on the kind of programming, that you are doing.
But I must say that I really had missed the fact that C++ does not allow
me to express integral constants in binary notation directly in one or
the other occasion.

I hope, I'm not getting a reply to this question of the kind: "Of-course
you can, just write a template and ask programmers to write:"

unsigned i = _b<0, 1, 0, 0>::value;

This is not something, that looks like intuitive code to me, compared to
the built-in capabilitis of the language as in

unsigned i = 0xff00U;

> Isn't it yet another "creative" effort on the committee's part?

I really do not understandand this part of your question. What has the
C++(?) committee to do with my example code?

Greetings from Bremen,

Daniel Krügler


--

John Shaw

unread,
Nov 7, 2011, 4:07:59 AM11/7/11
to
On Nov 6, 3:45 am, darkknight...@gmail.com wrote:
> On Fri, 4 Nov 2011 22:10:31 -0700 (PDT), Dave Abrahams
>
> I don't know what user defined literals are but it sounds like more
> obfuscated garbage which is what template meta-programming is. I've
> read some of your book on template meta-programming and I find it hard
> to believe that there's any real world use for such "gobbledegook". I
> bet there's an easier way to solve whatever problem template
> meta-programming is the solution for. Complexity costs. We need
> programming techniques and tools that allow average programmers to
> write understandable and maintainable software efficiently.
>


Interesting, I have found many real-world uses for such gobbledegook" and
the more support for it the better. As for techniques that allow the
average programmer to write understandable and maintainable code, they are
the beneficiaries of those who develop the meta templates. No one said they
had to write their own, but having the knowledge to do so has great
benifits.

Ok - I guess I am not your average programmer. Because I wrote a
meta-programming library to simplify my life. By using it I have removed
much of the complexity associated with cross-platform development. But anyone
using it would benefit.

The following does not deal with binary literal operators, but it should make
my point.

Example 1:
Using my meta-programming template 'required_integral' to define some required
types eliminates many compiler dependency problems. If one compiler defines an
'int' as 16-bits and another as 32-bits, it will continue to compile and work
as expected.

Advantages:
1. No complex compiler-dependent '#define' statements are required
2. You know at compile-time if the compiler supports the required types.
3. It is clean and avoids many pitfalls associated with crosss-
platform development.

Disadvantages:
1. None that I know of - Yet.

// START EXAMPLE 1:
typedef jrs::cttm::required_integral<unsigned, 8>::type utf8_char_t;
typedef jrs::cttm::required_integral<unsigned,16>::type utf16_char_t;
typedef jrs::cttm::required_integral<unsigned,32>::type utf32_char_t;
// END EXAMPLE 1

Example 2:
Using my meta-programming template 'sign_cast' to cast the unknown integer
type argument to its unsigned equivalent reduces the amount of repetive
code require. I could have written 3 additional overloaded functions for
every one of the many required functions, but this is cleaner and requires
less effort.

Advantages:
1. It avoids repetitive tasks that often lead to errors that are hard
to diagnose.
2. It is clean and easy to debug.

Disadvantages:
1. None that I know of - Yet.

// START EXAMPLE 2:
inline bool utf_IsLead(utf32_char_t) { ... }
inline bool utf_IsLead(utf16_char_t ch) { ... }
inline bool utf_IsLead(utf8_char_t ch) { ... }
template<typename CharT>
inline bool is_lead(CharT ch)
{
return utf_IsLead(cttm::sign_cast<unsigned>(ch));
}
// END EXAMPLE 2

The above examples are taken from real-wold code. The udefined templates
above represent some of the type-templates that I wish where defined in
the STL. But I learned more and had more fun of creating them
myself ;-)

Dave Abrahams

unread,
Nov 7, 2011, 4:11:25 AM11/7/11
to
on Sun Nov 06 2011, darkknight.21-AT-gmail.com wrote:

> I've read some of your book on template meta-programming and I find it
> hard to believe that there's any real world use for such
> "gobbledegook". I bet there's an easier way to solve whatever problem
> template meta-programming is the solution for.

I eagerly await your solutions.

> Complexity costs.

Yes.

> We need programming techniques and tools that allow average
> programmers to write understandable and maintainable software
> efficiently.

TMP enables library writers to build "tools that allow average
programmers to write understandable and maintainable software
efficiently." A great many Boost libraries takes advantage of TMP in
their implementations. Whatever your opinion of that code, many
"average programmers" find it to be an indispensable tool.

If you want to supply those tools, learning TMP might be worth your
time. If you just want to be an "average" user of those tools, you
might not want to make the effort.

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com


darkkn...@gmail.com

unread,
Nov 8, 2011, 6:49:46 PM11/8/11
to
On Mon, 7 Nov 2011 01:11:25 -0800 (PST), Dave Abrahams wrote:

>on Sun Nov 06 2011, darkknight.21-AT-gmail.com wrote:
>
>> I've read some of your book on template meta-programming and I find it
>> hard to believe that there's any real world use for such
>> "gobbledegook". I bet there's an easier way to solve whatever problem
>> template meta-programming is the solution for.
>
>I eagerly await your solutions.
>

I was hoping you had one already.

Actually I'm just taking a wild guess that since since the original
purpose of templates was nothing to do with meta programming and that
(some) template meta programs look ugly and esoteric, a purpose built
"meta language" could do the job much more simply. Maybe I'm just
biased towards state driven procedural programming.


--

Dave Abrahams

unread,
Nov 9, 2011, 1:57:12 AM11/9/11
to
on Tue Nov 08 2011, darkknight.21-AT-gmail.com wrote:

>>on Sun Nov 06 2011, darkknight.21-AT-gmail.com wrote:
>>
>>> I've read some of your book on template meta-programming and I find it
>>> hard to believe that there's any real world use for such
>>> "gobbledegook". I bet there's an easier way to solve whatever problem
>>> template meta-programming is the solution for.
>>
>>I eagerly await your solutions.
>>
>
> I was hoping you had one already.

Really, you were hoping I had an easier way than TMP to solve whatever
problem TMP is the solution for? I'm pretty sure I wouldn't have
written a book about TMP in that case.

> Actually I'm just taking a wild guess that since since the original
> purpose of templates was nothing to do with meta programming and that
> (some) template meta programs look ugly and esoteric, a purpose built
> "meta language" could do the job much more simply.

Definitely.

> Maybe I'm just biased towards state driven procedural programming.

Could be. Frankly I'm not sure what your position is here.

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com


Mathias Gaunard

unread,
Nov 9, 2011, 3:58:15 PM11/9/11
to
On Nov 3, 7:12 pm, Daniel Krügler <daniel.krueg...@googlemail.com>
wrote:

> Since gcc does currently not properly resolve using-declarations of
> literal operators, you need a using directive. Here is a short example
> code based on above implementation which demonstrates that the literals
> are evaluated during compile-time:
>
> using namespace tools;
>
> static_assert(0_b == 0, "Ouch");
> static_assert(1_b == 1, "Ouch");
> static_assert(01_b == 1, "Ouch");
> static_assert(10_b == 2, "Ouch");
> static_assert(11_b == 3, "Ouch");
> static_assert(00011_b == 3, "Ouch");
> static_assert(1000_b == 8, "Ouch");
> static_assert(1111_b == 15, "Ouch");
> static_assert(101101110111000001100101110_b == 96174894, "Ouch");
> static_assert(1110001100001010001001100011111101_b == 15236372733, "Ouch");

It's nice, but what's the compile-time overhead?

I once tried to allow hexadecimal floating-point literals with
something like this. The compile-time overhead was not acceptable.

Gennaro Prota

unread,
Nov 11, 2011, 8:23:57 AM11/11/11
to
On Mon, 07 Nov 2011 09:58:44 +0100, Daniel Kr=FCgler =

<daniel....@googlemail.com> wrote:

> Am 05.11.2011 00:43, schrieb Gennaro Prota:
>> On Thu, 03 Nov 2011 19:12:52 +0100, Daniel Kr=FCgler
>> <daniel....@googlemail.com> wrote:
>>
>>> Since gcc 4.7 has recently implemented user-defined literals, it is =
now
>>> finally possible to define a binary literal operator template that
>>> behaves very much like built-in literals.
>>
>> "Finally possible"? Apart from fun, what is the real-word need
>> for this stuff?
>
> It probably depends much on the kind of programming, that you are doin=
g.
> But I must say that I really had missed the fact that C++ does not all=
ow
> me to express integral constants in binary notation directly in one or=

> the other occasion.
>
> I hope, I'm not getting a reply to this question of the kind: "Of-cour=
se
> you can, just write a template and ask programmers to write:"
>
> unsigned i = _b<0, 1, 0, 0>::value;
>
> This is not something, that looks like intuitive code to me, compared =
to
> the built-in capabilitis of the language as in
>
> unsigned i = 0xff00U;
>
>> Isn't it yet another "creative" effort on the committee's part?
>
> I really do not understandand this part of your question. What has the=

> C++(?) committee to do with my example code?

Sorry, both "this stuff" and the subsequent comment were
referred to user-defined literals, in general, and not to your
code.

The feature is IMHO a premature generalization effort. And at
the end of the day binary literals aren't even there: you just
have a way to implement your own (there's nothing in the library
either, AFAICS).

That being said, I'm not going to convince anyone. And there
have been worse examples since C++03 (starting probably with
strings and I/O library).

Incidentally, last time I checked (very long ago) UDLs were
incompatible with C99's hexadecimal floating constants.

-- =

Gennaro Prota | name.surname gmail.com
Breeze C++ (preview): <http://sourceforge.net/projects/breeze/>
Do you need expertise in C++? I'm available.


Daniel Krügler

unread,
Nov 11, 2011, 2:29:06 PM11/11/11
to
On 2011-11-11 14:23, Gennaro Prota wrote:
> The feature is IMHO a premature generalization effort.

I disagree very much. This feature was added because it

a) had little impact on the overall core language
b) was an often asked request to allow to provide a concept of
"literals" for user-defined types as we have for built-ins. See

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2282.pdf
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2378.pdf
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2750.pdf

for a lot of motivating examples.

> And at the end of the day binary literals aren't even there: you just
> have a way to implement your own (there's nothing in the library
> either, AFAICS).

There is a very simple reason for the current lack of library support:
It was too late in the C++11 process to add one. There are several good
examples one could think of as possible additions in the future, e.g. _i
for a pure imaginary complex number, one could think of literals for
strings or for chrono components as well. But it would be even better to
wait for actual user experience before standardizing something upfront of.

> Incidentally, last time I checked (very long ago) UDLs were
> incompatible with C99's hexadecimal floating constants.

There are no longer anymore.

HTH & Greetings from Bremen,

Daniel Krügler

Reply all
Reply to author
Forward
0 new messages