c++ how i learned to stop worrying and love metaprogramming
TRANSCRIPT
Why metaprogramming?
6
Have the compiler generate the
correct program for you
• It knows things you don’t
• It will not be afraid to do tedious work
• It makes less mistakes than you
• Why write code when you could be
playing Baldur’s Gate 2 for the 10th
time?
Also: it’s awesome
A gentle introduction
7
int main(int argc, char ** argv)
{
static_assert(sizeof(int) == 4, "I want 32-bit integers!");
}
A more concrete example
8
#include <type_traits>
template <typename T>
T factorial(T v)
{
typedef typename std::integral_constant<T, 1> threshold;
static_assert(std::is_integral<T>::value, "I need an integral type");
return (v <= threshold::value) ? v : (v * factorial(v - 1));
}
A real metaprogram: compile time factorial
9
template <typename T, T v>
struct termination : std::conditional<v == 0, bool, void> {};
template <typename T, T v, typename Termination>
struct factorial_impl : std::integral_constant<T, v * factorial<T, v - 1>::type::value> {};
template <typename T, T v>
struct factorial_impl<T, v, bool> : std::integral_constant<T, 1> {};
template <typename T, T v, typename Termination = typename termination<T, v>::type>
struct factorial : factorial_impl<T, v, Termination> {};
The right code with tag dispatching
11
std::vector<int> v;
std::list<int> v;
template <typename Iterator>
void something_something_dark_side(Iterator first, Iterator last)
{
auto v = std::distance(first, last);
}
Wouldn’t it be cool to...
struct my_struct{
int alpha;std::string omega;
};
12
{"my_struct" : {
"alpha": 2,"omega": "boom"
}}
my_struct blah = { 2, ”boom” };auto boom = json::generate(json::from_fusion(blah));
Introducing Boost.Fusion
13
BOOST_FUSION_ADAPT_STRUCT(my_struct, (int, alpha)(std::string, omega))
• Compile time introspection
• Bridge between compile time and runtime
Example, set of various types:
boost::fusion::set<struct1, struct2> blah;
boost::fusion::at_key<struct1>(blah);
”Perfect” serialization
15
Goals
• Generate correct code
• Allocate memory only if needed
• Generate highly optimized code
• No ”if mess”
• Unintrusive
• More time for Baldur’s Gate 2
Implementing serialization
template <>struct codec<std::uint16_t, void>{
template <typename OutIt> static void encode(Outit & out,
boost::asio::mutable::buffer & sbuf, std::uint16_t i) {}
static boost::system::error_code decode(boost::asio::const_buffer & in,std::uint_16_t & i) {}
};
template <>struct scratch_size<std::uint16_t, void> :
boost::mpl::size_t<sizeof(std::uint16_t)> {};
16
Detect if alloc-free serialization is possible
17
struct static_size_tag { char pad; }; struct dynamic_size_tag { char pad[2]; };
template <typename T> struct is_static
{
template <typename U>
static static_size_tag dispatch(typename scratch_size<U>::type *) { return static_size_tag(); }
template <typename U> static dynamic_size_tag dispatch(...) { return dynamic_size_tag(); }
typedef is_static<T> type;
static const bool value = sizeof(dispatch<T>(nullptr)) == sizeof(static_size_tag);
};
The Metaprogrammer toolbox
18
• Clang 3.5+
• <type_traits>
• <tuples>
• Boost.MPL
• Boost.Fusion
• Boost.Hana - https://ldionne.github.io/hana/