Version 2006-05-24, by Eelis
This software has been released into the Public Domain
// Note: The following is all standard-conforming C++, this is not a hypothetical language extension.
#include "analogliterals.hpp"
#include <cassert>
int main ()
{
using namespace analog_literals::symbols;// Consider:
unsigned int a = 4;
// Have you ever felt that integer literals like "4" don't convey the true size of the value they denote? If so, use an analog integer literal instead:
unsigned int b = I---------I; assert( a == b );
// Due to the way C++ operators work, we must use N*2+1 dashes between the I's to get a value of N:
assert( I-I == 0 ); assert( I---I == 1 ); assert( I-----I == 2 ); assert( I-------I == 3 );
// These one-dimensional analog literals are of type analog_literals::line<N>, which is convertible to unsigned int.
// In some cases, two-dimensional analog literals are appropriate:
unsigned int c = ( o-----o
| !
! !
! !
o-----o ).area;
assert( c == (I-----I) * (I-------I) );
assert( ( o-----o
| !
! !
! !
! !
o-----o ).area == ( o---------o
| !
! !
o---------o ).area );// Two-dimensional analog literals are of type analog_literals::rectangle<X, Y> which exposes static member constants width, height, and area.
/* As an example use-case, imagine specifying window dimensions in a GUI toolkit API using:
window.dimensions = o-----------o
| !
! !
! !
! !
o-----------o ;Who said C++ was unintuitive!? */
// But wait, there's more. We can use three-dimensional analog literals, too:
assert( ( o-------------o
|L \
| L \
| L \
| o-------------o
| ! !
! ! !
o | !
L | !
L | !
L| !
o-------------o ).volume == ( o-------------o
| !
! !
! !
o-------------o ).area * int(I-------------I) );// Three-dimensional analog literals are of type analog_literals::cuboid<X, Y, Z> which exposes static member constants width, height, depth, and volume. In addition, three free-standing functions top, side, and front are provided which yield rectangles:
assert( top( o-------o
|L \
| L \
| o-------o
| ! !
! ! !
o | !
L | !
L| !
o-------o ) == ( o-------o
| !
! !
o-------o ) );// The current implementation has one restriction on cuboid dimensions: the height of a cuboid literal must be at least its depth + 2.
// Note that storing these literals directly in a variable requires you to specify the dimension sizes:
analog_literals::rectangle<4, 2> r = o---------o
| !
! !
o---------o;// This of course defeats the purpose of using the analog literal. C++0x's proposed `auto' feature would come in quite handy here. We can actually fix this problem partially (using the stack-ref-to-temporary's-base trick used by Alexandrescu's ScopeGuard), but we would no longer be able to use the values in ICE's, and frankly I think this madness has gone far enough already.
}
2006-05-24
2006-03-26
2005-08-ish
Initial version
analogliterals.hpp(download)
operator T () const { return T(); } };
template struct excls { excls operator! () const { return gen(); } };
template struct dashes: excls, 0>
{ dashes operator-- (int) const { return gen(); } };
template struct L_symbols {}; // represents a L|L|L|.. series
template L_symbols operator| (L_symbols, Lsymbol) { return gen(); }
template struct eL_symbols {}; // represents a !L|!L|!L|.. series
template eL_symbols operator| (eL_symbols, eLsymbol) { return gen(); }
dashes operator-- (line_end, int) { return gen(); }
excls operator! (line_end) { return gen(); }
// Result types
template struct line: L_symbols, 0>
{ static uint const length; operator uint () const { return len; } };
template struct rectangle { static uint const width, height, area; };
template struct cuboid { static uint const width, height, depth, volume; };
// Static members
template uint const line::length = len;
template uint const rectangle::width = x;
template uint const rectangle::height = y;
template uint const rectangle::area = x * y;
template uint const cuboid::width = x;
template uint const cuboid::height = y;
template uint const cuboid::depth = z;
template uint const cuboid::volume = x * y * z;
template rectangle front (cuboid) { return gen(); }
template rectangle side (cuboid) { return gen(); }
template rectangle top (cuboid) { return gen(); }
// Equality
template bool operator== (line, line) { return ax == bx; }
template bool operator== (rectangle, rectangle)
{ return ax == bx && ay == by; }
template
bool operator== (cuboid, cuboid) { return ax == bx && ay == by && az == bz; }
// Construction
// line
line<0> operator- (line_end, line_end) { return gen(); }
template line operator- (dashes, line_end) { return gen(); }
// rectangle
template struct lower_rectangle {}; // with lower right corner
template
lower_rectangle operator- (excls, excl_marks>, line_end)
{ return gen(); }
template rectangle operator| (line, lower_rectangle) { return gen(); }
// cuboid
template struct cuboid_top {};
template struct half_cuboid {};
// dimensions of complete cuboid known, rest is for show
template
cuboid_top operator| (L_symbols, n>, line) { return gen(); }
template
eL_symbols, 0> // todo: assert: n%3=2
operator| (cuboid_top, excls) { return gen(); }
template
cuboid operator| (eL_symbols, z>, lower_rectangle) { return gen(); }
// Convenience namespaces that can be "using namespace"'d:
namespace symbols
{
using analog_literals::o;
using analog_literals::I;
using analog_literals::L;
}
namespace shapes
{
using analog_literals::line;
using analog_literals::rectangle;
using analog_literals::cuboid;
}
} // analog_literals
#endif // header guard
#ifdef ANALOGLITERALS_TEST
int main ()
{
using namespace analog_literals::symbols;
using namespace analog_literals::shapes;
line<3>(I-------I);
rectangle<2, 3>(o-----o
| !
! !
! !
o-----o);
cuboid<6, 6, 3>(o-------------o
|L \
| L \
| L \
| o-------------o
| ! !
! ! !
o | !
L | !
L | !
L| !
o-------------o );
cuboid<3, 4, 2>(o-------o
|L \
| L \
| o-------o
| ! !
o | !
L | !
L| !
o-------o);
}
#endif // testing
]]>