Boost hana find type in set - c++

New to boost::hana and trying a simple experiment to find a type in a set of types and just print its typeid.name. However I am getting static_assert errors (NOTE: Xcode 7.2.1)
This is the code:
auto set = hana::make_set(hana::type_c<int>, hana::type_c<float>);
auto s = hana::adjust( set, hana::type_c<int>, [](auto x){ std::cout << typeid(x).name() << std::endl; });
The error is:
"hana::adjust(xs, value, f) requires 'xs' to be a Functor");
However this seems at odds with the documentation for adjust which states that xs needs to be a structure.
Any advice appreciated as I assume I'm missing something fundamental in my understanding.

The problem is that Hana uses functional programming terminology, where Functor means something different from what it typically is used to mean in C++ (i.e. a function object).
In the signature for adjust:
(auto&& xs, auto&& value, auto&& f)
adjust: F(T) × U × (T → T) → F(T)
then xs is F(T), a Functor over T; f is (T → T), a function object that maps values of T to T.
The other problem here is that lowercase and uppercase F refer to different objects within the signature.
Set is not a Functor, because of its invariant that values occur at most once. If you replace make_set with make_tuple (and ensure that your f returns a value), your code will compile (Example):
auto t = hana::make_tuple(hana::type_c<int>, hana::type_c<float>);
hana::adjust(t, hana::type_c<int>, [](auto x){ std::cout << typeid(x).name() << std::endl; return x; });
However, you should probably not be using hana::adjust here, as you don't care about the return value; instead, use hana::filter with hana::for_each (Example):
auto s = hana::make_set(hana::type_c<int>, hana::type_c<float>);
hana::for_each(hana::filter(hana::to_tuple(s), hana::equal.to(hana::type_c<int>)),
[](auto x){ std::cout << typeid(x).name() << std::endl; });

Related

Boost Hana filter a constexpr tuple

Super basic question about Boost Hana.
From the examples it seems I should be able to do the following:
int main() {
constexpr auto a = boost::hana::make_tuple(-1, 4, 5, -4);
constexpr auto b = boost::hana::filter(a, [](int elem) constexpr { boost::hana::bool_c<(elem > 0)>;});
}
However, I get
error: 'elem' is not a constant expression
which seems weird because I added constexpr wherever I could...
Is this at all possible? Or am I just missing something?
Note: I realize that you can achieve this with constexpr functions or something, but I would like to see how to do it with Hana as well, for educational purposes.
The return type must be statically deducible. However, you are returning different types depending on the argument.
You could do it, but not using hana::filter because that specifically moves into the runtime domain by putting the (statically known) tuple elements in (runtime) function arguments.
As soon as your predicate depends on more than statically known information (i.e. the types of the elements), it won't be constantly evaluated. The examples document how it could be used:
static_assert(hana::filter(hana::make_tuple(1, 2.0, 3, 4.0), is_integral) == hana::make_tuple(1, 3), "");
static_assert(hana::filter(hana::just(3), is_integral) == hana::just(3), "");
BOOST_HANA_CONSTANT_CHECK(hana::filter(hana::just(3.0), is_integral) == hana::nothing);
On the other hand, you can have your cake and eat it if you move the elements to the compile time domain:
Live On Coliru
constexpr auto a = hana::make_tuple(-1_c, 4_c, 5_c, -4_c);
constexpr auto b = hana::filter( //
a, //
[](auto elem) constexpr { return std::integral_constant<bool, (elem() > 0)>{}; } //
);
std::cout << "a:" << hana::size(a) << "\n";
std::cout << "b:" << hana::size(b) << "\n";
Prints
a:4
b:2

Making a list of generators (vector of lambdas) leads to very strange behavior with capture-by-reference

The following code is fairly similar to my actual application. Basically, I am trying to create a vector of functions so that I can generate a very large output in segments. I don't fully understand how the capture by reference [&] is working / should be working, and it's leading to some weird behavior.
#include <iostream>
#include <functional>
#include <vector>
using namespace std;
template <typename T>
T add(const T& a, const T& b) {
return a + b;
}
template <typename T>
T add(const T& a, const T& b, T x) {
return (add<T>(a,b)*x);
}
int main() {
std::cout << "Hello World!\n";
vector<function<long ()>> funks;
for (long i = 1; i < 12; ++i) {
//auto funky = std::bind(add<int>, i, i*i);
std::cout << "PROOF: " << add(i, i*i, 2L) << std::endl;
function<long ()> funky = [&]() -> long {
long V = i;
return add(V, V*V, 2L);
};
funks.push_back(funky);
}
for (auto&& x : funks) {
std::cout << x() << " ";
}
}
The output of running each x in funks is: [312, 312, 312 ... 312] corresponding to i = 13
However, I don't understand why this is the case, as I reinitialize V for each lambda, and the output should be [4, 12, 24, 40, ... 264]
It works when I change the capture clause to [=], but in my actual application the inputs will be quite large so I'd prefer to copy as few times as possible.
EDIT: I should clarify exactly what I'm looking for. I'd like to make a vector of N functions, [f_0, f_1, ... f_N], such that when calling f_i(), it calls F(V_i) for some large (known) function F and large V_i.
The reason I want to capture by reference is that I don't want to copy the V_i even once, but the result of my implementation is that every f_i() ends up calling F(V_N)
You are auto-capturing i by reference in your loop, but it's only a binding. The value is not actually used until after the loop, when calling the lambda. At that point, each call takes the captured "reference to i" (which is actually undefined behavior, given that i is no longer in scope), dereferences it and stores the value in V. You know the rest.
What is strange is that you are insisting on using references to integer values. It's likely the compiler is doing its best to inline these and just use plain copies, but you should consider that when you have a reference, you can often expect additional instructions to be generated to dereference that to a value. For primitive types, just copy.
Oh, and definitely capture i by value!!! As a matter of style, I prefer to be explicit about my captures:
function<long ()> funky = [i]() -> long {
long V = i;
return add(V, V*V, 2L);
};

Why structured bindings only work with auto

Structured bindings have been introduced with c++17. They give the ability to declare multiple variables initialised from a tuple or struct.
This code compiles using a c++17 compiler.
#include <iostream>
#include <tuple>
int main() {
auto tuple = std::make_tuple(1.0, 1);
auto [ d, i ] = tuple;
std::cout << "d=" << d << " i=" << i << '\n';
return 0;
}
If I don't declare the variables with auto I get the error
error: expected body of lambda expression
[d2 , i2] = tuple;
#include <iostream>
#include <tuple>
int main() {
auto tuple = std::make_tuple(1.0, 2);
double d2;
int i2;
[d2 , i2] = tuple;
return 0;
}
I used clang version 4.0.0 and the compile option -std=c++1z.
Can I assign existing variables to a structured binding? Do I need to use auto?
The error message your got is pretty indicative of why it's only allowed with auto: lack of ambiguity that will make the grammar even more context dependent.
A pair of square brackets at the start of an expression indicates a lambda. What you are asking is for the standard to specify that sometimes [d2 , i2] is the beginning of a lambda that captures d2 and i2 by value, and at other times it's an unpacking assignment. All based on what follows it.
It's just not worth the complexity to add it to the language. Especially, since as Some programmer dude noted, you already have std::tie to do what you want with tuples.
Not only that, std::tie allows you to ignore some of the unpacked values, something structured bindings don't support yet. So it all boils down to having a more limited form of syntactic sugar, to do something the standard library already does with tuples.
Oh, and if you are disgruntles that std::tie works only with tuples, you can expand it to work with any POD yourself. Just look at this magic_get implementation. One can apply the same idea to constexpr transform a POD into a tuple of reference that can be fed to std::tie. Something like this:
std::tie(d2, i2) = magic_unpack(/*some POD that isn't a tuple*/);
Also, you can using std::tie() to unpack the tuple into its individual components. Such as
#include <iostream>
#include <tuple>
int main() {
auto tuple = std::make_tuple(1.0, 1);
double d2;
int i2;
std::tie(d2, i2) = tuple;
std::cout << "d2=" << d2 << " i2=" << i2 << '\n';
return 0;
}

Invalid range expression of std::valarray in range for loop

I have a simple usage of traversing a temporary std::valarray expression in range for loop, but got error: invalid range expression ...
main.cpp
#include <iostream>
#include <valarray>
int main()
{
std::valarray<int> xxx {2,7,1,8,2,8};
std::valarray<int> zzz {xxx};
for (auto x : xxx + zzz) std::cout << x << std::endl;
return 0;
}
clang++ main.cpp -std=c++11
main.cpp:10:17: error: invalid range expression of type 'std::__1::__val_expr<std::__1::_BinaryOp<std::__1::plus<int>, std::__1::valarray<int>, std::__1::valarray<int> > >'; no viable 'begin' function available
for (auto x : xxx + zzz) std::cout << x << std::endl;
^ ~~~
Is there really a good reason that it does not compile as I expected?
Return type of the overloaded operator+ is valarray<T>, so theoretically, value of the expression should be a temporary instance of type valarray<T>.
Synopsis:
template<class T> valarray<T> operator+ (const valarray<T>& x, const valarray<T>& y);
Version: Apple LLVM version 8.0.0 (clang-800.0.38) Target: x86_64-apple-darwin15.6.0
Note following line works
for (auto x : xxx += zzz) std::cout << x << std::end;
As a "begin" and "end" are available for the operator+ return type, namely valarray<T> I'd say the error is wrong and it should compile.
What do you want to do?
If you want to traverse xxx do the for only in it:
for (const auto x : xxx) std::cout << x << std::endl;
But answering the basics of your question, the expression (xxx + yyy) is not iterable. If you want to do the for loop in both, you do two fors:
for (auto x : xxx) std::cout << x << std::endl;
for (auto x : zzz) std::cout << x << std::endl;
If you want to do it in a single loop, you can append both
xxx += yyy;
for (auto x : xxx) std::cout << x << std::endl;
PD from edit: The line
for (auto x : xxx += yyy) std::cout << x << std::endl;
works because it makes the append first and then iterates. Is equivalent to my last suggestion. But (xxx+yyy) is not iterable.
From your comment:
valrray::operator+(valarray) does not exist.
valrray::operator+=(valarray) does exist.
The range for loop uses the non-member std::begin and std::end, which are not required to exist for the return type of operator+ for std::valarray.
The portable syntax is
for(auto x : std::valarray<int>(xxx + zzz))
This is noted on cppreference and in the standard under 26.7.1[valarray.syn]p4.1
This is a really good question. The reason is the behavior of A+B over valarrays.
Let us see what I mean by this.
First, try these lines.
std::valarray<int> xxx {2,7,1,8,2,8};
std::valarray<int> zzz {xxx};
auto t=xxx+zzz;
cout<<typeid(t).name()<<endl;
cout<<typeid(xxx).name()<<endl;
cout<<typeid(xxx+zzz).name()<<endl;
you will notice that they are not the same, and this is due to the definition of the + operator here https://en.cppreference.com/w/cpp/numeric/valarray/operator_arith3
As it is written the type is deduced. This means that its behavior is similar to auto. The question then is why does it not deduce the same type, valarray. Probably, it is due to a compiler optimization feature, or maybe it is a mistake, but it is clear that the reference does not force the compiler to deduce the same type. The thing is the deduced type happens to be not iterable by a range based for loop.
Please let me know if anything is not clear.

How to use auto keyword in C++

I have C++ code with a type auto:
auto T = reads a JSON
I need to print the content of the T using
cout << T << endl;
It is not working. Can you help me?
With C++11, you can declare a variable or an object without specifying its specific type by using auto.1 For example:
auto i = 42; // i has type int
double f();
auto d = f(); // d has type double
The type of a variable declared with auto is deduced from its initializer. Thus, an initialization is required:
auto i; // ERROR: can’t dedulce the type of i
Additional qualifiers are allowed. For example:
static auto vat = 0.19;
Using auto is especially useful where the type is a pretty long and/or complicated expression. For example:
vector<string> v; ... auto pos = v.begin(); // pos has type vector<string>::iterator
auto l = [] (int x) -> bool { // l has the type of a lambda ..., // taking an int and returning a bool };
In short auto can deduce any type .Your program is not working because it is possible that it is not able to parse JSON or compiler is old (where auto is not supported .Can you specifically let me know the error you got ?
auto in C++ means "set variable type for type of initialization expression", in your case whatever that "reads a JSON" expression returns. You cannot output that type to std::cout because operator<< is not defined for such type, there could be many possible reasons as operator not provided, you suppose to use something else, missing header etc. Solution would depend on actual type.
Ok ! Before telling you how to use auto, I must tell you it's one of the best features of C++11 & has made C++ even more efficient by :-
Reducing amount of code
Enforcing initialization
Increasing genericity (In C++17)
Firstly auto has only 1 job. It will deduce the type of an object by the value passed to it. For ex :-
auto x = 5;
This means that x is an integer whose value is 5. Whenever you are using auto you must initialize the variable (which is a good thing) & you cannot use auto on multiple types in a statement. For ex :-
auto x; // illegal ! x isn't initialized so compiler cannot dduce it's type
auto z=5, y=7; // legal because z & y are both integers
auto a=8, ch= 'c'; // illegal ! an integer & a character in a single statement, hence type deduction ambiguity
The cream of auto is not in intializing int, char, etc data types. It's more handy for classes like iterators. For ex :-
vector<int> v;
vector<int>::iterator i1 = v.begin();
auto i2 = v.begin(); // see how auto reduces the code length
This can be even more obvious in for loops :-
for (vector<int>::iterator i = v.begin(); i!=v.end(); ++i);
Can be reduced to :-
for (auto i = v.begin(), i!=v.end(); ++i);
If you are not happy with the above then this may inspire you to use auto :-
vector< map <int, vector<string> > >::iterator i1 = v.begin(); // where v is the vector of maps of ints & vectors of strings !!!!
auto i2 = v.begin();
The genericity I was talking about is in passing values to functions by auto. Like :-
void add (auto x, auto y)
{
cout << x+y << '\n';
}
This is not possible in current standards & has been proposed for C++17. This is likely to increase the generic ability of the functions without the use of templates. However this syntax is possible for lambda functions :-
auto l = [](auto x, auto y) { return x+y; } // legal from C++14 onwards
However be careful when using braces with lambda because you may think that :-
auto x = {5};
Is an integer but it is actually an intializer_list<int> type object. I can explain a hell lot about auto but I guess for now this is more than enough.