diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
index d4a3682a..5d4a6602 100644
--- a/doc/Doxyfile.in
+++ b/doc/Doxyfile.in
@@ -228,6 +228,8 @@ TAB_SIZE = 4
# "Side Effects:". You can put \n's in the value part of an alias to insert
# newlines.
+ALIASES += strike{1}="
\1
"
+
ALIASES +=value="\ref concepts_value"
ALIASES +=values="\ref concepts_value \"Values\""
ALIASES +=optional="\ref concepts_optional"
diff --git a/doc/css/metal.css b/doc/css/metal.css
index 7916ddeb..14b35637 100644
--- a/doc/css/metal.css
+++ b/doc/css/metal.css
@@ -129,6 +129,10 @@ span.octicon {
margin-right: 5px;
}
+.strike {
+ text-decoration: line-through;
+}
+
#footer {
height: 100px;
font-size: 0.9em;
diff --git a/doc/manual.md b/doc/manual.md
index 7ff9e9c4..04e8d05f 100644
--- a/doc/manual.md
+++ b/doc/manual.md
@@ -2,7 +2,7 @@
\tableofcontents
-Metal is a [portable](\ref portability) header-only [C++11][C++11] library
+Metal is a [portable](\ref portability) header-only [C++11] library
designed to make [template metaprogramming][tmp] enjoyable.
To that end, it provides a powerful high-level [abstraction](\ref concepts) for
compile-time algorithms that mimic the [standard algorithms library][algorithm],
@@ -252,7 +252,7 @@ specialization of [std::integral_constant][integral].
### See Also
-metal::number, metal::boolean, metal::integer
+metal::number, metal::boolean, metal::integer, metal::character
Optional {#concepts_optional}
--------------------------------------------------------------------------------
@@ -477,6 +477,200 @@ given an expression `metal::expr`,
`metal::expr_t<...>` is equivalent to `typename metal::expr<...>::type`.
}
+Metal in Action {#metal_in_action}
+================================================================================
+
+Enough theory, lets see some action!
+
+Parsing Raw Literals {#parsing_raw_literals}
+--------------------------------------------------------------------------------
+
+If you ever considered augmenting [`std::tuple`][tuple],
+so that instead of the rather odd [`std::get()`][get]
+
+\snippet tutorial/literal.cpp teaser_1
+
+one could just use the more intuitive subscript operator `[N]`,
+
+\strike{
+\snippet tutorial/literal.cpp teaser_2
+}
+
+chances are you realized the hard way
+that the reason why such an operator is not overloaded by default is because
+there's simply no way of overloading such an operator!
+
+All is not lost however if you can live with the subscript operator taking an
+object of type `std::integral_constant`, or in Metal's parlance [Number],
+instead of an usual integral value.
+
+\snippet tutorial/literal.cpp super_tuple
+
+\snippet tutorial/literal.cpp teaser_3
+
+Neat isn't it?
+Now we need a [literal operator][literal] `_c` that encodes an integral value
+as a [Number]. Sounds simple enough, right?
+
+\strike{
+\snippet tutorial/literal.cpp naive
+}
+
+Not really. While `constexpr` tells the compiler the value returned by
+`operator ""_c` might be a compile time constant,
+it tells no such thing about its argument.
+We are thus left no other option but to parse raw literals ourselves,
+in other words, we are in for some fun!
+
+### The Raw Literal Operator Template
+
+Raw literal operator templates are defined as a nullary function templated over
+`char...`, such as
+
+\snippet tutorial/literal.cpp raw
+
+where `tokens...` are mapped to the exact characters that make up the literal,
+including the prefixes `0x` and `0b`
+
+\snippet tutorial/literal.cpp raw_examples_1
+
+as well as the digit separator `'` introduced by [C++14]
+
+\snippet tutorial/literal.cpp raw_examples_2
+
+### The `operator ""_c`
+
+We start by defining our very own literal operator `_c`.
+It simply wraps each token into a `metal::character` and forwards them to an
+[Expression] that effectively parses the [Number], we'll call it,
+suggestively, `make_number`.
+
+\snippet tutorial/literal.cpp _c
+
+### Resolving the Radix
+
+In its turn `make_number` strips the prefix, if any, thus resolving the radix,
+then forwards the remaining tokens to `parse_digits`,
+which is in charge of translating the raw characters to a [List] of
+integral [Numbers].
+The radix and digits are then forwarded to `compute`, which adds up the digits
+according to the radix.
+
+\snippet tutorial/literal.cpp make_number
+
+Notice that we followed the notation used by Metal and defined `make_number_t`
+as an alias to `typename make_number<>::type` to save typing.
+
+### Parsing the Digits
+
+To parse the characters into the corresponding integral, we need first to remove
+all digit separators.
+That can be easily accomplished using `metal::remove`, which takes a [List] `l`
+and a [Value] `v` and returns another [List] that contains every element from
+`l` and in the same order, except for those that are identical to `v`.
+
+\snippet tutorial/literal.cpp remove
+
+The remaining digits can then be transformed into the corresponding
+[Numbers] using `metal::transform`, which takes a [Lambda] `lbd` and a
+[List] `l` and returns another [List] containing the results of *invoking* `lbd`
+for each element in `l`.
+
+ [lbd(l[0]), lbd(l[1]), ..., lbd(l[n-2]), lbd(l[n-1])]
+
+First we need an [Expression] that maps characters to
+[Numbers] from which we can construct our `lbd`.
+We'll call it `to_number` and it is rather trivial.
+
+\snippet tutorial/literal.cpp to_number
+
+Now we can transform characters to [Numbers].
+
+\snippet tutorial/literal.cpp transform_1
+
+That peculiar `metal::_1` is a placeholder and it works like this:
+when `to_number` is invoked with some argument,
+`metal::_1` will be substituted for that argument and only then `to_number`
+is *evaluated*.
+
+Putting it all together we have
+
+\snippet tutorial/literal.cpp parse_digits
+
+### Computing the Number
+
+Now we turn our attention to `compute`.
+It takes the radix and a list of [Numbers] representing the digits and is in
+charge of adding up the digits according to the radix, that is
+
+ D0*radix^(n-1) + D1*radix^(n-2) + ... + D{n-2}*radix + D{n-1}
+
+The first thing we notice is that the *ith* digit actually corresponds to the
+(n-1-i)th power of the radix, so, to make things simpler,
+we need to `metal::reverse` the order of digits.
+
+\snippet tutorial/literal.cpp reverse
+
+Then we have
+
+ D0 + D1*radix + ... + D{n-2}*radix^(n-2) + D{n-1}*radix^(n-1)
+
+Now we need to `metal::enumerate` the exponents that correspond to each digit.
+
+\snippet tutorial/literal.cpp enumerate
+
+This version of `metal::enumerate` takes two [Numbers], `start` and `size`,
+and returns a [List] containing a sequence of [Numbers] beginning with `start`
+and ending in `size - 1`.
+
+ [start, start + 1, ..., size - 2, size - 1]
+
+\note{
+All [Numbers] in the sequence have the same type as `start`
+regardless of the type of `size`.
+}
+
+The next step is to compute each term of the sum.
+We'll be using `metal::transform` again, but this time it takes a *binary*
+[Lambda] `lbd` and two [Lists] `l1` and `l2` and returns a new [List] formed by
+*invoking* `lbd` for the elements of `l1` and `l2` pairwise.
+
+ [lbd(l1[0], l2[0]), lbd(l1[1], l2[1]), ..., lbd(l1[n-2], l2[n-2]), lbd(l1[n-1], l2[n-1])]
+
+\snippet tutorial/literal.cpp transform_2
+
+Here again `metal::_1` and `metal::_2` are placeholders that get substituted for
+the first and second arguments with which `lbd` is invoked,
+prior to the recursive *evaluation* of the [Expressions] that form the [Lambda].
+
+Finally we need to sum up the terms, so basically we need to invoke `metal::add`
+for the elements contained in a [List].
+That's exactly what `metal::apply` is for.
+
+\snippet tutorial/literal.cpp sum
+
+Here we used `metal::lambda` which is basically a synonym for
+`metal::add, metal::arg>`,
+where `n` is the number of arguments with which `metal::lambda` is
+invoked, that is the size of the [List] in this particular case.
+This way we don't need to care about the actual number of arguments.
+
+We now have all the pieces needed to define `compute`.
+
+\snippet tutorial/literal.cpp compute
+
+And we are done.
+
+\snippet tutorial/literal.cpp test_1
+
+It even works for very long binary literals.
+
+\snippet tutorial/literal.cpp test_2
+
+And also ignores digit separators.
+
+\snippet tutorial/literal.cpp test_3
+
[Value]: \ref concepts_value
[Values]: \ref concepts_value
[Optional]: \ref concepts_optional
@@ -496,6 +690,7 @@ given an expression `metal::expr`,
[Placeholders]: \ref placeholders
[C++11]: http://en.wikipedia.org/wiki/C%2B%2B11
+[C++14]: http://en.wikipedia.org/wiki/C%2B%2B14
[JavaScript]: http://en.wikipedia.org/wiki/JavaScript
[higher-order]: http://en.wikipedia.org/wiki/Higher-order_lambda
[first-class]: http://en.wikipedia.org/wiki/First-class_citizen
@@ -516,6 +711,9 @@ given an expression `metal::expr`,
[decltype]: http://en.cppreference.com/w/cpp/language/decltype
[constexpr]: http://en.cppreference.com/w/cpp/language/constexpr
[integral]: http://en.cppreference.com/w/cpp/types/integral_constant
+[tuple]: http://en.cppreference.com/w/cpp/utility/tuple
+[get]: http://en.cppreference.com/w/cpp/utility/tuple/get
+[literal]: http://en.cppreference.com/w/cpp/language/user_literal
[CMake]: http://cmake.org/
[CMake.doc]: http://cmake.org/documentation/
diff --git a/example/src/tutorial/literal.cpp b/example/src/tutorial/literal.cpp
new file mode 100644
index 00000000..ffa7f810
--- /dev/null
+++ b/example/src/tutorial/literal.cpp
@@ -0,0 +1,329 @@
+// Copyright Bruno Dutra 2015
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at http://boost.org/LICENSEmetal::_1_0.txt)
+
+#include
+
+#include
+#include
+
+#include "example.hpp"
+
+#if 0
+///[naive]
+constexpr auto operator ""_c(long long i)
+ -> std::integral_constant {
+ return {};
+}
+///[naive]
+#endif
+
+///[raw]
+template
+constexpr auto operator ""/**/_raw()
+ -> metal::list...> {
+ return {};
+}
+///[raw]
+
+///[raw_examples_1]
+static_assert(std::is_same<
+ decltype(42_raw),
+ metal::list, metal::character<'2'>>
+>::value, "");
+
+static_assert(std::is_same<
+ decltype(0x42_raw),
+ metal::list<
+ metal::character<'0'>, metal::character<'x'>,
+ metal::character<'4'>,metal::character<'2'>
+ >
+>::value, "");
+///[raw_examples_1]
+
+#ifdef __cpp_digit_separators
+///[raw_examples_2]
+static_assert(std::is_same<
+ decltype(4'2_raw),
+ metal::list, metal::character<'\''>, metal::character<'2'>>
+>::value, "");
+///[raw_examples_2]
+
+HIDDEN(namespace)
+{
+///[remove]
+using tokens = metal::list<
+ metal::character<'4'>,
+ metal::character<'\''>,
+ metal::character<'2'>
+>;
+
+static_assert(std::is_same<
+ metal::remove_t>,
+ metal::list, metal::character<'2'>>
+>::value, "");
+///[remove]
+}
+#endif
+
+///[to_number]
+template
+struct to_number :
+ metal::conditional<
+ metal::equal_to_t>, metal::number,
+ metal::equal_to_t>, metal::number,
+ metal::equal_to_t>, metal::number,
+ metal::equal_to_t>, metal::number,
+ metal::equal_to_t>, metal::number,
+ metal::equal_to_t>, metal::number,
+ metal::equal_to_t>, metal::number,
+ metal::equal_to_t>, metal::number,
+ metal::equal_to_t>, metal::number,
+ metal::equal_to_t>, metal::number,
+ metal::equal_to_t>, metal::number,
+ metal::equal_to_t>, metal::number,
+ metal::equal_to_t>, metal::number,
+ metal::equal_to_t>, metal::number,
+ metal::equal_to_t>, metal::number,
+ metal::equal_to_t>, metal::number,
+ metal::equal_to_t>, metal::number,
+ metal::equal_to_t>, metal::number,
+ metal::equal_to_t>, metal::number,
+ metal::equal_to_t>, metal::number,
+ metal::equal_to_t>, metal::number,
+ metal::equal_to_t>, metal::number
+ >
+{};
+///[to_number]
+
+HIDDEN(namespace)
+{
+///[transform_1]
+using digits = metal::list**/metal::character<'4'>, metal::character<'2'>>;
+
+static_assert(std::is_same<
+ metal::transform_t, digits>,
+ metal::list, metal::number>
+>::value, "");
+///[transform_1]
+}
+
+HIDDEN(namespace)
+{
+///[reverse]
+using digits = metal::list**/metal::number, metal::number>;
+
+static_assert(std::is_same<
+ metal::reverse_t,
+ metal::list, metal::number>
+>::value, "");
+///[reverse]
+}
+
+HIDDEN(namespace)
+{
+///[enumerate]
+using digits = metal::list**/metal::number, metal::number>;
+
+static_assert(std::is_same<
+ metal::enumerate_t, metal::size_t>,
+ metal::list, metal::number>
+>::value, "");
+///[enumerate]
+}
+
+HIDDEN(namespace)
+{
+///[transform_2]
+using radix = metal::number;
+using digits = metal::list**/metal::number, metal::number>;
+using exponents = metal::list**/metal::number, metal::number>;
+
+static_assert(std::is_same<
+ metal::transform_t<
+ metal::mul>,
+ digits,
+ exponents
+ >,
+ metal::list, metal::number>
+>::value, "");
+///[transform_2]
+}
+
+HIDDEN(namespace)
+{
+///[sum]
+using terms = metal::list**/metal::number, metal::number>;
+
+static_assert(std::is_same<
+ metal::apply_t, terms>,
+ metal::number
+>::value, "");
+///[sum]
+}
+
+///[compute]
+template
+struct compute :
+ metal::apply<
+ metal::lambda,
+ metal::transform_t<
+ metal::mul>,
+ metal::reverse_t,
+ metal::enumerate_t<
+ metal::number,
+ metal::size_t
+ >
+ >
+ >
+{};
+///[compute]
+
+///[parse_digits]
+template
+struct parse_digits :
+ metal::transform<
+ to_number,
+ metal::remove_t, metal::character<'\''>>
+ >
+{};
+
+template
+using parse_digits_t = typename parse_digits::type;
+///[parse_digits]
+
+///[make_number]
+template
+struct make_number :
+ compute, parse_digits_t>
+{};
+
+template
+struct make_number, tokens...> :
+ compute, parse_digits_t>
+{};
+
+template
+struct make_number, metal::character<'x'>, tokens...> :
+ compute, parse_digits_t>
+{};
+
+template
+struct make_number, metal::character<'X'>, tokens...> :
+ compute, parse_digits_t>
+{};
+
+template
+struct make_number, metal::character<'b'>, tokens...> :
+ compute, parse_digits_t>
+{};
+
+template
+struct make_number, metal::character<'B'>, tokens...> :
+ compute, parse_digits_t>
+{};
+
+template
+using make_number_t = typename make_number::type;
+///[make_number]
+
+///[_c]
+template
+constexpr auto operator ""/**/_c()
+ -> make_number_t...> {
+ return {};
+}
+///[_c]
+
+///[test_1]
+static_assert(std::is_same<
+ decltype(01234567_c), //octal
+ metal::number
+>::value, "");
+
+static_assert(std::is_same<
+ decltype(123456789_c), //decimal
+ metal::number
+>::value, "");
+
+static_assert(std::is_same<
+ decltype(0xABCDEF_c), //hexadecimal
+ metal::number
+>::value, "");
+///[test_1]
+
+static_assert(std::is_same<
+ decltype(0Xabcdef_c),
+ metal::number
+>::value, "");
+
+
+#if __cpp_binary_literals
+///[test_2]
+static_assert(std::is_same<
+ decltype(0b111101101011011101011010101100101011110001000111000111000111000_c),
+ metal::number
+>::value, "");
+///[test_2]
+
+static_assert(std::is_same<
+ decltype(0B111101101011011101011010101100101011110001000111000111000111000_c),
+ metal::number
+>::value, "");
+#endif
+
+#ifdef __cpp_digit_separators
+///[test_3]
+static_assert(std::is_same<
+ decltype(1'2'3'4'5'6'7'8'9_c),
+ metal::number
+>::value, "");
+///[test_3]
+#endif
+
+#if __cpp_constexpr < 201304
+template
+struct SuperTuple :
+ std::tuple
+{
+ template
+ constexpr SuperTuple(U&&... args) :
+ std::tuple(std::forward(args)...)
+ {}
+
+ template
+ constexpr auto operator [](metal::number) const
+ -> metal::at_t> {
+ return std::get(*this);
+ }
+};
+#else
+///[super_tuple]
+template
+struct SuperTuple :
+ std::tuple
+{
+ using std::tuple::tuple;
+
+ template
+ constexpr auto operator [](metal::number)
+ -> metal::at_t>& {
+ return std::get(*this);
+ }
+};
+///[super_tuple]
+#endif
+
+///[teaser_1]
+static_assert(std::get<1>(std::tuple{42, 'a', 2.5}) == 'a', "");
+///[teaser_1]
+
+#if 0
+///[teaser_2]
+static_assert(SuperTuple{42, 'a', 2.5}[1] == 'a', "");
+///[teaser_2]
+#endif
+
+///[teaser_3]
+static_assert(SuperTuple{42, 'a', 2.5}[1_c] == 'a', "");
+///[teaser_3]