Filtering a tuple in boost hana - c++

template<class... Ts, class T>
constexpr auto contains(T&&){
auto types = hana::to<hana::tuple_tag>(hana::tuple_t<Ts...>);
return hana::bool_c<hana::find(types, hana::type_c<T>) != hana::nothing>;
}
auto ht = hana::make_tuple(1,2,3,'c');
auto ht1 = hana::filter(ht, [](auto t){
return contains<int,float,double>(t);
});
//prints 0
std::cout << hana::size(ht1) << std::endl;
I am not sure if I am using boost hana correctly but contains seems to work.
std::cout << contains<int,float,double>(5) << std::endl; // 1
std::cout << contains<int,float,double>('c') << std::endl; // 0
std::cout << contains<int,float,double>(5.0f) << std::endl; // 1
Why is the size of ht1 0?

The problem here actually has nothing to do with Hana, it has to do with the way universal references are deduced. Just to clear up things, hana::type_c<T> == hana::type_c<U> is precisely equivalent to std::is_same<T, U>{}. There is no reference or cv-qualifier removing when comparing hana::types. You can look at various articles (like this or this) for these rules.
Now, let me go through your code and modify some things, with comments. First,
auto types = hana::to<hana::tuple_tag>(hana::tuple_t<Ts...>);
is redundant, because you're already creating a hana::tuple with hana::tuple_t. Hence, hana::tuple_t<T...> only is sufficient. Secondly, there's this line:
return hana::bool_c<hana::find(types, hana::type_c<T>) != hana::nothing>;
Instead of checking hana::find(...) != hana::nothing, I would instead use hana::contains, which expresses your intent better and might be more optimized too. In general, and especially with a metaprogramming library with Hana, don't try to reason as to what will be faster. Just state your intent as clearly as possible and hope for me to do my job properly on the implementation side :-). Hence, you'll end up with
return hana::bool_c<hana::contains(types, hana::type_c<T>)>;
Now, that hana::bool_c<...> really is redundant, because hana::contains already returns a boolean integral_constant. Hence, the above is equivalent to the simpler
return hana::contains(types, hana::type_c<T>);
Finally, putting all the bits together and simplifying, you get
template<class... Ts, class T>
constexpr auto contains(T&&){
return hana::contains(hana::tuple_t<Ts...>, hana::type_c<T>);
}
I'm personally not a fan of taking the T&& as an argument, when all you want is actually the type of that object. Indeed, that forces you to actually provide an object to contains function, which might be unwieldy in some circumstances (what if you don't have an object around?). Furthermore, it can be confusing to be comparing values with types:
contains<int, char, double>(3.5) // wtf, 3.5 is not in [int, char, double]!
Instead, I would write the following if it was my own code:
template<class... Ts, class T>
constexpr auto contains(T type){
return hana::contains(hana::tuple_t<Ts...>, type);
}
// and then use it like
contains<int, char, double>(hana::type_c<double>)
But that is part of the interface of your function, and I guess you are a better judge than I to know what your needs are in terms of interface.

The problem is the T&&, I think it deduces the type to be of type T& which means that hana::type_c<T> != hana::type_c<T&> The fix is to leave the && because they are unnecessary.
template<class... Ts, class T>
constexpr auto contains(T){
auto types = hana::tuple_t<Ts...>;
return hana::find(types, hana::type_c<T>) != hana::nothing;
}

Just to add to your answer, your ht1 was calling contains with t an lvalue. The following demonstrates T&& in the case of passing an rvalue and an lvalue:
#include<boost/hana.hpp>
namespace hana = boost::hana;
template<class T>
void test1(T&&) {
static_assert(hana::type_c<T> == hana::type_c<int>, "");
}
int main() {
static_assert(hana::type_c<int> != hana::type_c<int&&>, "");
test1(5);
int x = 5;
test1(x); //fails
}
clang output:
main.cpp:7:3: error: static_assert failed ""
static_assert(hana::type_c<T> == hana::type_c<int>, "");
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:14:3: note: in instantiation of function template specialization 'test1<int &>' requested here
test1(x); //fails
^
1 error generated.

Related

Get tuple element at runtime

I know that it is possible to get a random tuple element at runtime. Behind the scenes, make_integer_sequence and integer_sequence can get all elements at compile time and offer access to these elements at runtime.
But my problem is that it seems only to be possible to access the elements of a random index only with a lambda or function pointer. I would like to get the lambda to return the element-reference so that I could get something like this:
auto myElement = runtime_get(mytuple, 5);
I don't know how I could do this. Working with templates isn't that new to me but templates can get very difficult to understand if they become complex. I'm trying to learn more about them by playing a little bit with the tuple-stuff.
I think, this should work: runtime_get<std::string>(0, mytuple), so the type is predetermined.
Yes, this is certainly possible, but you need to do something if the runtime index isn't the right type. For example, throw an exception.
Here's one sample implementation, but note that I condensed it at the expense of some readability. Member function pointers and templated lambdas is possibly the worst combination of features the language has to offer, but it was pretty concise (live example):
template<typename Result, typename... Ts>
auto runtime_get(std::size_t i, std::tuple<Ts...>& t) -> Result& {
using Tuple = std::tuple<Ts...>;
// A set of functions to get the element at one specific index
auto get_at_index = []<std::size_t I>(Tuple& tuple) -> Result& {
if constexpr (std::is_same_v<std::tuple_element_t<I, Tuple>, Result>) {
return std::get<I>(tuple);
} else {
throw std::runtime_error("Index does not contain the right type");
}
};
// Regular index_sequence trick to get a pack of indices
return [&]<std::size_t... Is>(std::index_sequence<Is...>) -> Result& {
// The type of a single member function pointer of the closure type, using awkward memfun syntax
using FPtr = auto(decltype(get_at_index)::*)(Tuple&) const -> Result&;
// An array of said memfun pointers, each for one known index
FPtr fptrs[sizeof...(Ts)]{&decltype(get_at_index)::template operator()<Is>...};
// Invoke the correct pointer
return (get_at_index.*(fptrs[i]))(t);
}(std::index_sequence_for<Ts...>());
}
int main() {
std::tuple<std::string, int, double, std::string> t{"abc", 2, 5.9, "def"};
for (int i = 0; i < 4; ++i) {
try {
std::string& s = runtime_get<std::string>(i, t);
std::cout << "Success: " << s << '\n';
} catch (const std::runtime_error& ex) {
std::cout << "Failure: " << ex.what() << '\n';
}
}
}
Success: abc
Failure: Index does not contain the right type
Failure: Index does not contain the right type
Success: def
This is just the lvalue reference version, you might need other overloads. If you want a more reusable bit of trickery for the runtime-to-compile-time index conversion that you can hide away in a header, check out the std::call proposal.
Note also that this can be built out of a callback-based solution:
template<typename Result, typename... Ts>
auto runtime_get(std::size_t i, std::tuple<Ts...>& t) -> Result& {
return callback_get(i, t, [](auto& elem) -> Result& { /* same implementation as get_at_index */ });
}
The key point is that types must be resolved at compile-time. In the case of a template as a callback, that callback is being instantiated for every possible type regardless of whether that instatiation is actually used at runtime. You end up with N different callback functions, one for each possible case the program could encounter. There's no analogue for a simple variable.
Therefore, you need to condense N possibilities down to the same behaviour. This can be done as above by choosing a specific type and throwing (or returning an empty optional) on a mismatch. This can also be done by returning a variant, which covers all possible types, but doesn't actually bring you any closer to overcoming the impossible part of this problemā€”std::visit uses the same callback mechanism where each possible type needs to be compiled against the given callback.

Limitations of std::result_of for lambdas in C++14

I have a working piece of C++17 code that I would like to port to C++14 (project's constraints). The code allocates a functor on the heap, based on the lambda returned by a provider.
decltype(auto) fun_provider(std::string msg)
{
return [msg](){ std::cout << msg << std::endl; };
}
int main()
{
auto fun = std::make_unique<
std::invoke_result_t<decltype(fun_provider), std::string>
>(fun_provider("Provided functor"));
(*fun.get())()
}
// output: "Provided functor"
The point is, it avoids hardcoding lambda type as std::function<void()>. Up to my best knowledge, the closure type is unspecified and such construction would imply unnecessary copy of the closure object (hope that's correct).
I would like to achieve the same goal with C++14, is it possible? I tried few constructions with std::result_of and/or decltype but didn't succeed so far.
How about routing fun_provider's return value through another pass of template deduction?
template <class T>
auto to_unique(T&& orig) {
using BaseType = std::remove_cv_t<std::remove_reference_t<T>>;
return std::make_unique<BaseType>(std::forward<T>(orig));
}
int main()
{
auto fun = to_unique(fun_provider("Provided functor"));
(*fun.get())();
}
Is this approach not viable?
auto fun = std::make_unique<
decltype(fun_provider(std::declval<std::string>()))
>(fun_provider("Provided functor"));
The use of std::declval isn't even necessary; std::string{} instead of std::declval<std::string>() is just fine.
Just for the sake of completeness and to answer the original question.
The correct solution using std::result_of_t would look like this:
auto fun = std::make_unique<
std::result_of_t<decltype(&fun_provider)(std::string)>
>(fun_provider("Provided functor"));

Mutate return type of a lambda

The full context of this problem is unfortunately too involved to explain, but suffice to say it involves some complicated template metaprogramming and I find myself having to do some funny things. I've tried to boil down an issue I've encountered into a minimal example, so the question may seem awkward. If it's possible to do this I'd be interested to know how, if not I'd be interested in hearing possible alternatives.
I'd like to create a function that takes as input a lambda function that may return void or something else. If it does return void, I'd like to convert it into an identical lambda that, instead of returning void, returns true.
template <typename InputFuncType>
auto function_converter(InputFuncType lambda_func)
{
// I also need to figure out how to deduce the return type of lambda_func
// might be something like this.
if constexpr (std::is_same<std::result_of<InputFuncType>::type, void>::value)
{
// Current best guess. Note that in the context of the converter, I don't explicitly know
// lambda_func's input type, so I'm not sure how to do something like this.
return [](InputFuncType::input_args_t... args) {lambda_func(args); return true;};
}
return lambda_func;
}
// target usage
const auto lam1 = [](int a) {return;};
const auto lam2 = function_converter(lam1);
int x = 4;
lam1(x); // returns void
const bool y2 = lam2(x); // returns true
I'm using c++17.
A little redundant, I suppose, but the following wrapper should works
template <typename InputFuncType>
auto function_converter (InputFuncType lf)
{
return [=](auto && ... args)
{
using RT = decltype(lf(std::forward<decltype(args)>(args)...));
if constexpr ( true == std::is_same_v<void, RT> )
{
lf(std::forward<decltype(args)>(args)...);
return true;
}
else
return lf(std::forward<decltype(args)>(args)...);
};
}
Substantially, the idea is transfer the check, about the returned type, inside the internal lambda.

How to make lambdas work with std::nullopt

Background
I have a series of lambdas that perform different checks on the captured variables and return std::nullopt if the check failed. return std::nullopt is the first return statement. Then, if the check succeeded, they go on and compute the value.
Problem
The types of return expressions are not consistent, e.g. std::nullopt_t cannot be converted to std::optional<T>, even though the other way around works. In particular, I'd like the following code to compile and run, printing 2:
#include <functional>
#include <utility>
#include <optional>
int x = 3;
auto lambda = [](){
if (x == 2)
return std::nullopt;
return std::optional(2);
};
#include <iostream>
int main () {
using return_type = std::invoke_result_t<decltype(lambda)>;
static_assert(std::is_same<return_type, std::optional<int>>{},
"return type is still std::nullopt_t");
std::cout << lambda().value() << '\n';
}
Wandbox Demo.
Thoughts
I believe that I need to use std::common_type<Args...> somewhere, but I can neither enforce presence of it or deduce Args, as it might require language support.
Instead of using template type deduction to infer the return type of the lambda, why not explicitly specify that return type?
auto lambda = []() -> std::optional<int> {
if (x == 2)
return std::nullopt;
return 2;
};
std::common_type is commonly with templates, which you don't have.
I suggest to stick with a single return statement and explicitly specified result type without using nullopt at all. It looks somewhat misleading when a function returns either an integer or a nullopt. Especially if the function was longer. Also if value type was something with an explicit constructor then use of emplace allows to avoid typing value type name again.
auto lambda = []()
{
std::optional<int> result{};
if(2 != x)
{
result.emplace(2);
}
return result;
};

Generate new type whenever function called in C++

Is it possible to generate new type whenever a function is called?
I've read that each lambda has its own unique type, so I've tried:
template<class T, class F> struct Tag { };
template<class T>
auto func(const T &t) -> auto
{
auto f = [] () {};
return Tag<T, decltype(f)>();
}
static_assert(!std::is_same_v<decltype(func(0)), decltype(func(1))>, "type should be different.");
But, static_assert fails.
Can I make func() return a value of different type whenever func() called regardless of type T and the value of t?
No, not when the function is called. Types are generated at compile time, not at runtime.
Have a look at the question Can the 'type' of a lambda expression be expressed? Here is a code based on an answer from there.
#include <iostream>
#include <set>
int main()
{
auto n = [](int l, int r) { return l > r; };
auto m = [](int l, int r) { return l > r; };
std::set<int, decltype(n)> s(n);
std::set<int, decltype(m)> ss(m);
std::set<int, decltype(m)> sss(m);
std::cout << (std::is_same<decltype(s), decltype(ss)>::value ? "same" : "different") << '\n';
std::cout << (std::is_same<decltype(ss), decltype(sss)>::value ? "same" : "different") << '\n';
}
Result:
different
same
C++ is a statically typed language, which means the types only exist in the source code, and there is little trace of them left in the runtime.
Lambdas are no exception - they do have unique types, but those are defined at the compile time.
Templates can indeed be used to generate new types, and that is possible because templates are evaluated at compile time and therefore only exist in the source code as well.
So the strict answer is no, you cannot generate new types when the function is called, as function calls happen in runtime.
This being said, you can achieve pretty much any desirable flexibility in C++ with some clever design, just check out some common design patterns.