I'm going through Boost.Hana's User Manual to learn more about template meta programming and functional programming in C++.
As regards the Real world example, I still miss a few bits, all concentrated in the definition of the following function:
template<typename Any, typename Default, typename Case, typename ...Rest>
auto process(Any a, std::type_index const& t, Default default_, Case& case_, Rest ...rest) {
using T = typename decltype(+hana::first(case_))::type;
return typeid(T) == t ? hana::second(case_)(*boost::unsafe_any_cast<T>(&a))
: process(a, t, default_, rest...);
};
Here are my doubts and questions:
Regarding the using
directive, I do understand that T
is meant to be the type which is stored in the first
entry of case_
, which is a pair obtained with hana::make_pair
, but why is that so convoluted? I'm a bit confused by all those ::type
, decltype
, typename
, and hana::type_c
. How do they interact with each other (in this case, if the question seems to general)?
+
which is needed, really puzzles me too. What is it for?Once I take for granted that T
is that type I need, why do I compare it by typeid(T) == t
?
std::type_index
I read that The type_index
class is a wrapper class around a std::type_info
object,std::type_info
I read that The class type_info
holds implementation-specific information about a type, including the name of the type and means to compare two types for equality or collating order,typeid
I read (with reference to the use typeid(type)
) Refers to a std::type_info
object representing the type type,which all seem relevant, but I don't get exactly how typeid(T)
, which is of class std::type_info
, is compared to std::type_index
, which is comes from calling the type
member function on a
, which I don't know where it comes from. I hope someone can help me understand this point.
In the return statement for when typeid(T) == t
is true, why is hana::second(case_)(*boost::unsafe_any_cast<T>(&a))
needed and hana::second(case_)(a)
is not working?
I'll try to answer the question about that using
line:
case_
is a variable of type hana::pair
created by hana::make_pair(hana::type_c<T>, f)
(the first parameter is a wrapper around a type)hana::first(case_)
returns the first item of the pair (the hana::type_c wrapper around the type)+hana::first(case_)
uses the unary plus to convert the value from an lvalue to an rvalue (see https://www.boost.org/doc/libs/1_68_0/libs/hana/doc/html/structboost_1_1hana_1_1type.html)decltype(+hana::first(case_))
evaluates to the type of the first item of the pair (that hana::type_c wrapper)decltype(+hana::first(case_))::type
returns the actual type of the first item of the pair (whatever the type was that was constructed inside hana::type_c)using T = typename decltype(+hana::first(case_))::type;
names that original type as T
(the typename
bit is needed because C++ is a complicated language and sometimes the compiler needs a hint about whether a thing is a type or not)You need some machinery to extract that original type that was passed to hana::make_pair - if you were building something to solve only your particular problem you would make it simpler, but they need to make the library so generic that it will solve everybody's problems and that adds complexity.
As for that second return
line:
The whole premise of the example is that switch_
is passed a boost::any and it calls the right lambda with the contents of the boost::any.
hana::second(case_)
is one of the lambdas originally given to switch_
so if you use hana::second(case_)(a)
then a boost::any gets passed to your lambda but the code inside the lambda isn't expecting a boost::any so the error message says std::to_string doesn't accept a boost::any.
You could actually use hana::second(case_)(a)
and then cast the boost::any parameter back to the original type inside the lambda. That would actually work fine, but I think that is something switch_
should be doing for you so that the lambda gets the type you expect.
It's just unfortunate that boost::any requires such a terrible cast syntax.