Language C++
(most extreme template metaprogramming)
| Date: | 12/04/11 |
| Author: | Henrik Theiling |
| URL: | http://www.theiling.de/ |
| Comments: | 0 |
| Info: | n/a |
| Score: |
// -*- Mode: C++ -*-
// Oct 2011 by Henrik Theiling
// Licence: BSD
// Checked to work with g++-4.6.2 -std=c++0x
// Base char type for the strings: you can very well use char32_t, but unfortunately,
// the compiler will not show it as a character in its messages, so to demonstrate
// 'readable' type names, we use char.
typedef char Char;
// If
template<bool Cond, typename Then, typename Else>
struct If {
typedef Then Type;
};
template<typename Then, typename Else>
struct If<false, Then, Else> {
typedef Else Type;
};
// String
template<Char... string>
struct String {
// The funny thing is that we do not store the string at all:
// It is only stored in the type itself. If you want a
// C string, use 'CArray<char,...>::value'.
};
// Conversion to C values:
template<typename Elem, typename String>
struct CArray;
template<typename Elem, Char... string>
struct CArray< Elem, String<string...> > {
enum { size = sizeof...(string) };
static Elem const value[size + 1];
};
template<typename Elem, Char... string>
Elem const CArray<Elem, String<string...> >::value[] = { string..., '{CODE}' };
// Edit a string, list style:
template<typename String>
struct Car;
template<Char first, Char... rest>
struct Car< String<first, rest... > > {
enum { value = first };
};
template<typename String>
struct Cdr;
template<Char first, Char... rest>
struct Cdr< String<first, rest... > > {
typedef String<rest...> Type;
};
template<typename String, int n>
struct Nth
: public Nth< typename Cdr<String>::Type, n - 1>
{};
template<typename String>
struct Nth< String, 0 >
: public Car< String >
{};
template<Char car, typename cdr>
struct Conc;
template<Char first, Char... rest>
struct Conc< first, String<rest...> >
{
typedef String<first, rest...> Type;
};
// Concatenate strings:
template<typename... Strings>
struct Concat;
template<typename String>
struct Concat<String>
{
typedef String Type;
};
template<
Char... part1,
Char... part2>
struct Concat< String<part1...>,
String<part2...> >
{
typedef String<part1..., part2...> Type;
};
template<typename First, typename Second, typename... Rest>
struct Concat<First,Second,Rest...>
: public Concat< typename Concat<First,Second>::Type, Rest...>
{};
// Join: similar to Concat, but adds a string in between each element.
template<typename Separator, typename... Strings>
struct Join;
template<typename Separator>
struct Join<Separator>
{
typedef String<> Type;
};
template<typename Separator, typename Single>
struct Join<Separator,Single>
{
typedef Single Type;
};
template<typename Separator, typename First, typename... Rest>
struct Join<Separator,First,Rest...>
: public Concat<
First,
Separator,
typename Join<Separator, Rest...>::Type >
{};
// Stringify integers:
enum class Show0 { no, yes };
template<unsigned long long num, Show0 show0 = Show0::yes>
struct Unsigned2String {
typedef
typename Concat<
typename Unsigned2String< (num / 10), Show0::no >::Type,
String<('0' + (num % 10))>
>::Type
Type;
};
template<>
struct Unsigned2String<0, Show0::yes> {
typedef String<'0'> Type;
};
template<>
struct Unsigned2String<0, Show0::no> {
typedef String<> Type;
};
// Convert a single letter to upper case:
// (FIXME: add Unicode support)
template<Char orig>
struct ToUpper {
enum { value = orig };
};
template<> struct ToUpper<'a'> { enum { value = 'A' }; };
template<> struct ToUpper<'b'> { enum { value = 'B' }; };
template<> struct ToUpper<'c'> { enum { value = 'C' }; };
template<> struct ToUpper<'d'> { enum { value = 'D' }; };
template<> struct ToUpper<'e'> { enum { value = 'E' }; };
template<> struct ToUpper<'f'> { enum { value = 'F' }; };
template<> struct ToUpper<'g'> { enum { value = 'G' }; };
template<> struct ToUpper<'h'> { enum { value = 'H' }; };
template<> struct ToUpper<'i'> { enum { value = 'I' }; };
template<> struct ToUpper<'j'> { enum { value = 'J' }; };
template<> struct ToUpper<'k'> { enum { value = 'K' }; };
template<> struct ToUpper<'l'> { enum { value = 'L' }; };
template<> struct ToUpper<'m'> { enum { value = 'M' }; };
template<> struct ToUpper<'n'> { enum { value = 'N' }; };
template<> struct ToUpper<'o'> { enum { value = 'O' }; };
template<> struct ToUpper<'p'> { enum { value = 'P' }; };
template<> struct ToUpper<'q'> { enum { value = 'Q' }; };
template<> struct ToUpper<'r'> { enum { value = 'R' }; };
template<> struct ToUpper<'s'> { enum { value = 'S' }; };
template<> struct ToUpper<'t'> { enum { value = 'T' }; };
template<> struct ToUpper<'u'> { enum { value = 'U' }; };
template<> struct ToUpper<'v'> { enum { value = 'V' }; };
template<> struct ToUpper<'w'> { enum { value = 'W' }; };
template<> struct ToUpper<'x'> { enum { value = 'X' }; };
template<> struct ToUpper<'y'> { enum { value = 'Y' }; };
template<> struct ToUpper<'z'> { enum { value = 'Z' }; };
// Change the first character of a string to upper case:
template<typename String>
struct Capitalise
: public Conc<
ToUpper< Car<String>::value >::value,
typename Cdr<String>::Type >
{};
template<>
struct Capitalise< String<> >
{
typedef String<> Type;
};
// Sentence components:
typedef String<' '> _SPACE_;
typedef String<'\n'> _LINEBREAK_;
typedef String<'.'> _PERIOD_;
typedef String<',',' '> _COMMA_SPACE_;
typedef String<'a','n','d'> _and_;
typedef String<'a','r','o','u','n','d'> _around_;
typedef String<'b','e','e','r'> _beer_;
typedef String<'b','o','t','t','l','e'> _bottle_;
typedef String<'b','u','y'> _buy_;
typedef String<'d','o','w','n'> _down_;
typedef String<'g','o'> _go_;
typedef String<'i','t'> _it_;
typedef String<'m','o','r','e'> _more_;
typedef String<'n','o'> _no_;
typedef String<'o','f'> _of_;
typedef String<'o','n','e'> _one_;
typedef String<'o','n'> _on_;
typedef String<'p','a','s','s'> _pass_;
typedef String<'s','o','m','e'> _some_;
typedef String<'s','t','o','r','e'> _store_;
typedef String<'t','a','k','e'> _take_;
typedef String<'t','h','e'> _the_;
typedef String<'t','o'> _to_;
typedef String<'w','a','l','l'> _wall_;
// Pluralisation: the default is to add an 's':
// Irregular plurals can be added by specilising PluralOf<>.
// But we don't need that.
template<typename Singular>
struct PluralOf
: public Concat<Singular, String<'s'> >
{};
// Singular or Plural depending on a number:
template<unsigned count, typename Singular>
struct SingularOrPlural
: public If<
(count == 1),
Singular,
typename PluralOf<Singular>::Type >
{};
// Add a number in front of a noun and adjust the pluralisation
// of the noun accordingly:
template<unsigned count, typename Singular>
struct CountNoun
: public Concat<
typename Unsigned2String<count>::Type,
_SPACE_,
typename SingularOrPlural <count,Singular>::Type >
{};
// 'N Units of beer':
template<int count, typename Unit>
struct NUnitsOfBeer
: public Join<
_SPACE_,
typename CountNoun<count,Unit>::Type, _of_, _beer_>
{};
template<typename Unit>
struct NUnitsOfBeer<0,Unit>
: public Join<
_SPACE_,
_no_, _more_, typename PluralOf<Unit>::Type, _of_, _beer_>
{};
// 'N Units of beer on the wall':
template<int count, typename Unit>
struct NUnitsOfBeerOnTheWall
: public Join<
_SPACE_,
typename NUnitsOfBeer<count,Unit>::Type, _on_, _the_, _wall_ >
{};
// Last line of verse:
template<int count, int totalCount, typename Unit>
struct NMinus1UnitsOfBeerOnTheWall
: public Concat<
typename Join<
_SPACE_,
_take_, _one_, _down_, _and_, _pass_, _it_, _around_
>::Type, _COMMA_SPACE_,
typename NUnitsOfBeerOnTheWall<count - 1,Unit>::Type
>
{};
template<int totalCount, typename Unit>
struct NMinus1UnitsOfBeerOnTheWall<0,totalCount,Unit>
: public Concat<
typename Join<
_SPACE_,
_go_, _to_, _the_, _store_, _and_, _buy_, _some_, _more_
>::Type, _COMMA_SPACE_,
typename NUnitsOfBeerOnTheWall<totalCount, Unit>::Type
>
{};
// One Verse:
template<int count, int totalCount, typename Unit>
struct Verse
{
typedef
typename Concat<
typename NUnitsOfBeerOnTheWall<count,Unit>::Type, _COMMA_SPACE_,
typename NUnitsOfBeer<count,Unit>::Type, _PERIOD_
>::Type
Line1;
typedef
typename Concat<
typename NMinus1UnitsOfBeerOnTheWall<count,totalCount,Unit>::Type, _PERIOD_
>::Type
Line2;
typedef
typename Concat<
typename Capitalise<Line1>::Type, _LINEBREAK_,
typename Capitalise<Line2>::Type, _LINEBREAK_
>::Type
Type;
};
// Bottles:
template<int count, int totalCount, typename Unit>
struct MakeSong
{
typedef
typename Concat<
typename Verse<count, totalCount, Unit>::Type,
_LINEBREAK_,
typename MakeSong<count - 1, totalCount, Unit>::Type
>::Type
Type;
};
template<int totalCount, typename Unit>
struct MakeSong<0,totalCount,Unit>
: public Verse<0, totalCount, Unit>
{};
// Make the song:
template<int count, typename Unit>
struct Song: public MakeSong<count,count,Unit>
{};
//////////////////////////////////////////////////////////////////////
// Usage:
typedef Song<99,_bottle_>::Type TheBeerSong;
//////////////////////////////////////////////////////////////////////
// Usage 1: Let the compiler sing the song
#if 1
static int i= TheBeerSong();
// cause an error => the compiler prints the type name...
#endif
//////////////////////////////////////////////////////////////////////
// Usage 2: Print the song
#if 0
#include <stdio.h>
int main(void)
{
puts(CArray<char,TheBeerSong>::value);
return 0;
}
#endif
Download Source | Write Comment
Alternative Versions
| Version | Author | Date | Comments | Rate |
|---|---|---|---|---|
| extreme template metaprogramming | Richard Wolf | 04/20/05 | 5 | |
| Preprocessor & self-include recursion | Chocapic | 02/27/07 | 6 | |
| hacking style | Tim Robinson | 04/20/05 | 14 | |
| feature creep | Jono | 04/27/09 | 1 | |
| meta programming | Arion Lei | 04/20/05 | 5 | |
| object-oriented version | Tim Robinson | 04/20/05 | 4 | |
| 7 | Jono | 04/15/09 | 0 | |
| ob fuscated | Tapi (Paddy O'Brien) | 08/11/05 | 4 | |
| GUI version | Martyn Davies | 05/28/05 | 1 |
Download Source | Write Comment
Add Comment
Please provide a value for the fields Name,
Comment and Security Code.
This is a gravatar-friendly website.
E-mail addresses will never be shown.
Enter your e-mail address to use your gravatar.
Please don't post large portions of code here! Use the form to submit new examples or updates instead!
Comments