Understanding Boost.Hana Quick start - c++

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)?
Well, that + 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?
From std::type_index I read that The type_index class is a wrapper class around a std::type_info object,
from 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,
and from 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.

Related

auto as type template parameter in concept requirement clause [duplicate]

I am playing with concepts and hit a roadblock. Or maybe it is just my mind that is blocked.
I want to create a class that buffers a "bulk-readable" data source. Such a datasource should have a member function that accepts an OutputIterator and has a signature like:
template<typename It>
size_t read(It firstItem, size_t max)
My idea was to define a BulkReadable concept similar to:
template<typename Source>
concept bool BulkReadable =
requires(Source s, Iter out, size_t max) {
{s.read(out, max)} -> size_t;
};
I am having trouble specifying Iter. I could add another typename to the template parameter list, but then the Buffer class that wants to use the concept would need to specify the type of that parameter.
The ideal way how I would like to use the concept is:
template<BulkReadable Source>
class Buffer {
public:
Source& input:
Buffer(Source& input) : input(input){}
...
Is this approach even viable? If yes, how can I require a templated method signature if I do not want/can specify the type?
This is a common problem of asking the wrong question of a concept, where you're trying to use them like you would a base class interface. With base classes, you're declaring the exact, specific functions that the derived classes are to implement. You want the user to implement exactly the function you say they must.
With concepts, you approach the issue from the other direction: what usage are you trying to create?
At some point in your code, you have some object, some iterator, and a size. And you're going to take that object, call a function by passing it the iterator and the size, and you expect a response back of a certain type. And this process has some meaning.
Then that is your concept. It's a concept that is based on at least 2 parameters: the type of the object and the iterator type. So that's what you should create.
If you have this BulkReadable constraint, then you must have some interface constrained on it. An interface that's going to call read. To call read, that interface must have an iterator.
So here are the options:
The interface is given an iterator type (directly or indirectly) by the user. If that's the case, then you just use that type in the function's BulkReadable constraint. If the iterator type is based on a complex set of operations on parameters, then you'll have to do some computations to compute the iterator type.
The iterator is statically determined. Then just use the known iterator type in the constraint.
The point being that, at the point where you're going to try to call read, you know what the iterator type is. And therefore, you can constrain things using that type. Your concept therefore is not really BulkReadable, but BulkReadableFrom.
In short, you shouldn't want to constrain a type on being able to take any type (or any type within some constraints). Check constraints against the actual types you're going to use them with, preferably at the point where they become relevant.

Using std::is_convertible with std::type_index

I have an vector of std::type_index, which indicate the trait types that a particular node has. I'm implementing a function which checks whether the node supports a particular type. It looks like this:
std::vector<std::type_index> traits;
...
template <typename T>
bool hasTrait() {
return std::find(traits.begin(), traits.end(), typeid(T)) != traits.end();
}
However, this won't work if type T is a derived type of some base type in traits. In order to fix this problem, I wanted to use std::is_convertible.
However, I only have access to the std::type_index of the type, so I can't do that. Something like this would be required: std::is_convertible<traitTypeIndex::type, T>
At first I would mention that it is surely impossible with std::is_convertible. Like all other things from type_traits, std::is_convertibleis a purely compile-time thing. But you want it to give you answer during the run-time for some run-time argument (which is type_index).
The second question is if this check can be implemented at all for arbitrary polymorphic types (by "arbitrary" I mean that you don't have any specific design-time or run-time information). I think that it's not impossible because the whole run-time reflection we have in C++ is dynamic_cast (when RTTI is on). However, even in dynamic_cast we have one semi-dynamic argument (pointer or reference) and one static (type to which we wan't to convert). I write semi-dynamic because it needs to be a pointer or reference to some certain type, it cannot absolutely type-erased argument (like void*). I believe that to check dynamically if one of two types is the inheritor of the other one we need more support from a run-time.

Why std::function has no function_type or equivalent member type?

From here it seems to me that the std::function has no function_type or equivalent member type to export the actual type used to initialize it.
It has result_type, argument_type, as well as first_argument_type and second_argument_type, but nothing like the type above mentioned.
Why it doesn't offer such a type as part of its interface?
There will be for sure a good reason for that, but I can't figure out what's that reason, so I'm just curious to find it out.
For I know the first question will be why do you need it, well, imagine that I want to do something like std::is_same<F1::function_type, F2::function_type>::value to check if their underlying types are the same in a sfinae evaluation, where it's fine if they contain different functions as long as the signs are the same.
I admit that it doesn't make much sense, to be honest the question is just for the sake of curiosity.
EDIT
As noted by #Brian in the comments of his answer, I misused the term initialize when I wrote:
to export the actual type used to initialize it
What I'm interested in is the template argument indeed.
As an example, for a std::function<void(S&, int)> (where S is a struct), function_type would be void(S&, int).
I think you're asking the wrong question. The right question is: why should there be such a member type?
If, say, you write a function template that can accept any specialization of std::function, then the template parameter will already be immediately available to you:
template <typename T>
void f(std::function<T> F) {
// you wouldn't write decltype(F)::function_type here; you'd just write T
}
The more inconvenient case is the one in which you have some function like
template <typename Callable>
void f(Callable C);
Here, you have no guarantee that Callable is a std::function specialization, so even if std::function<T> had typedef T function_type, you wouldn't want to access Callable::function_type for an arbitrary callable. So it wouldn't be of any use here.
The right question is: why do some standard library classes expose their template parameters, for example, containers of T (which have typedef T value_type)? The answer is that the standard has a specific set of requirements that the container types have to satisfy, which reflects a design goal that it should be possible to write generic algorithms that work on different types of containers, not all of which would be template specializations of the form C<T>. It then makes sense to mandate that all containers expose value_type because that's the only uniform way of extracting the element type from arbitrary containers.
If std::function were also an instance of some Callable concept, it would make sense to have the requirement that there is a function_type typedef so that code accepting any Callable could access the function type. But that's not the case, and it's not useful to have it for only the single template std::function.
You can easily write one:
template < typename T >
struct function_type;
template < typename Sig >
struct function_type<std::function<Sig>> { using type = Sig; };
On your terminology: instantiate is the word you're looking for. You are looking for the type that the template was instantiated with.
The only people who know why it isn't a member type are those who designed the feature and those who voted it in (maybe). It could simply be something nobody thought of. It does seem a bit obvious, but that's in hindsight from the perspective of wanting it.

C++ equivalent of Rust's Result<T, E> type?

I like using std::experimental::optional in my C++ code, but the problem is value_or requires the default value to be of the same type as the optional's value.
This doesn't work very well when I want an optional that either contains an int or contains an error message.
I guess I could use a union struct that has a boolean to indicate if the value is there or it's an error, but it sure would be nice if C++ just had a Result<T, E> type like Rust.
Is there any such type? Why hasn't Boost implemented it?
Result is really much more useful than Option, and surely the people at Boost are aware of its existence. Maybe I'll go read the Rust implementation and then copy it to C++?
Ex:
// Function either returns a file descriptor for a listening socket or fails
// and returns a nullopt value.
// My issue: error messages are distributed via perror.
std::experimental::optional<int> get_tcp_listener(const char *ip_and_port);
// You can use value_or to handle error, but the error message isn't included!
// I have to write my own error logger that is contained within
// get_tcp_listener. I would really appreciate if it returned the error
// message on failure, rather than an error value.
int fd = get_tcp_listener("127.0.0.1:9123").value_or(-1);
// Rust has a type which does what I'm talking about:
let fd = match get_tcp_listener("127.0.0.1:9123") {
Ok(fd) => fd,
Err(msg) => { log_error(msg); return; },
}
In c++17, optional<T> is an asymmetric type safe union of T and nothingness (nullopt_t). You can query if it has a T with explicit operator bool, and get the T out with unary *. The asymmetry means that optional "prefers" to be a T, which is why unqualified operations (like * or operator bool) refer to its Tness.
In c++17 variant<A,B,C> from paper n4218 is a symmetric type safe union of A, B and C (etc). boost::variant is always engaged, and std::variant is almost always engaged (in order to preserve some exception guarantees, it can become valueless by exception if the types it store don't have the right exception semantics).
As it is symmetric, there is no unique type for unary * to return, and explicit operator bool cannot say much of interest, so neither are supported.
Instead, you have to visit it, or query it for particular types.
In c++23 std::expected<T, E> from paper n4015 is an asymmetric type-safe union. It is either a T, or an E. But like optional, it "prefers" to be a T; it has an explicit operator bool that tells you if it is a T, and unary * gets the T.
In a sense, expected<T,E> is an optional<T>, but when empty instead of wasting the space it stores an E, which you can query.
Result<T,E> seems close to expected<T,E> (note that as of n4015, the order of parameters are swapped compared to Result, but the published version did not).
What you are looking for is exactly Alexandrescu's Expected. I recommend listening to his talk for an in depth understanding: https://www.youtube.com/watch?v=kaI4R0Ng4E8. He actually goes through the implementation line by line, and you can easily write it yourself and use it well after that.
Variant is a more general tool, it can be coerced to do what you want but you're better off with expected.
If not only boost is involved u can use result. This is nice single header container.
optional by design either contains a value of some type or nothing.
You may be looking for something like Boost::Variant.
This is not yet part of the standard library, although something like it may be eventually.
Since this was asked, the C++23 standard's std::expected does exactly this. A summarizing quote from Cpp Reference:
The class template std::expected provides a way to store either of two values. An object of std::expected at any given time either holds an expected value of type T, or an unexpected value of type E. std::expected is never valueless.

Determine type of templated function result at compile-time?

I'm not sure this is possible, but is there a way, using template programming magic, to define a function that has different return values depending on what input it takes?
Potentially:
template<typename resultType>
resultType GetResult(const std::string &key); // where the value of key may change resultType
template<typename keyType, typename resultType>
resultType GetResult(keyType key);
Now, I know that the above isn't correct. To use the first one, you'd have to know what resultType was before calling the function. However, I've learned that a lot of "impossible" things are often made possible with just another layer (or two) of indirection. I just can't seem to find the right way to do it.
The second option tickles my brain though. I feel like I should be able to define some other helper object that maps strings to types (or whatever) and then the compile-time result of that will call GetResult with the appropriate template parameter.
Edit: Assume that the types used for resultType are unrelated. There is not an interface that can be tested for the "real" type (maybe it could be an int and a MyClass *).
Edit 2: The real-world usage is that I've got a third-party object that contains a collection of Widgets, Gadgets, etc. You can ask for these by string id (prefixed with a type, conveniently), but you have to parse the string to find out that you need to call "collectionInstance.getWidget(id)". My plan was to write a thin wrapper object that would intelligently know how to get at these internal objects.
No. You cannot make the return type, defined at compile-time, depend on a run-time value.
You could return a boost::variant or a boost::any, though.
You need a helper metafunction that will map those types in your second example. typename helper<keyType>::type would then be your return type and the keyType template parameter would be removed. Your helper metafunction would need to create a type typedef depending on its template parameter. You may find boost::mpl::map a helpful utility for this task and possibly BOOST_STRONG_TYPEDEF to define different types based on std::string.
Based on your edit, what you want is not what you're asking for. What you need is:
1) A way to store a variable of any type among X,Y,Z unrelated types.
2) A way to parse your string to find out which function to call in order to get your variable.
The first can be solved with boost::variant.
The second can be solved by a two part solution. First is the parsing routine that returns a function or object that will actually make the appropriate call. The second is the set of objects or functions that make this call and assign to the variant. Thus you'd end up with something like so:
boost::variant<X,Y,Z> get_result(std::string stuff)
{
return parser::instance().get_call(stuff).make_call(stuff);
}
If you actually need to separate the type information from the rest of the string then get_call will need to do that for you or you'll need another function that separates the string into two pieces that you then supply to the above calls.
You can hack this with the cast operator. I make no claims about this being good programming practice, but it is doable:
template <typename keyType>
class GetResult
{
keyType mkey;
GetResult(keyType key) : mkey(key) {}
template <typename resultType>
operator resultType()
{
//do stuff here that returns result type
}
}