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 rectangle
s:
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(); } }; templatestruct 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 ]]>