How to create vector from specific values from array? - c++

I will start from code:
#include <iostream>
#include <vector>
using namespace std;
struct A
{
int color;
A(int p_f) : field(p_f) {}
};
int main ()
{
A la[4] = {A(3),A(5),A(2),A(1)};
std::vector<int> lv = {begin(la).color, end(la).color};//I would like to create vector from specific value from array la
for (std::vector<int>::iterator it = fifth.begin(); it != fifth.end(); ++it) std::cout << ' ' << *it;
return 0;
}
Generally I would like to create a vector from specific values from array.
As you can see la is A array and I would like to create vector containing not the whole la array, but only color.
vector(int) not vector(A), which vector{3,5,2,1}, so not A, but only int color. It can be done using in C++11 also. Thanks.

This should work.
std::vector<int> lv;
std::transform(std::begin(la), std::end(la), std::back_inserter(lv), [](const A& a){
return a.color;
});
Also here is another way:
Refactor your structure to get color from a method:
struct A
{
int color;
A(int p_f) : color(p_f) {}
int getColor() const {
return color;
}
};
In this case you may use bind:
std::transform(std::begin(la), std::end(la), std::back_inserter(lv), std::bind(&A::getColor, std::placeholders::_1));
Or you may also use std::mem_fn to method which is a bit shorter (thanks to #Piotr S.):
std::transform(std::begin(la), std::end(la), std::back_inserter(lv), std::mem_fn(&A::getColor));
Or you may use std::mem_fn to data member. In this case you don't even need to implement a getter method:
std::transform(std::begin(la), std::end(la), std::back_inserter(lv), std::mem_fn(&A::color));

Following may help:
namespace detail
{
using std::begin;
using std::end;
template <typename Container, typename F>
auto RetrieveTransformation(const Container& c, F f)
-> std::vector<std::decay_t<decltype(f(*begin(c)))>>
{
// if `F` return `const T&`, we want `std::vector<T>`,
// so we remove reference and cv qualifier with `decay_t`.
//
// That handles additionally the case of lambda
// The return type of lambda [](const std::string&s) { return s;}
// - is `const std::string` for msvc
// - is `std::string` for for gcc
// (Note that the return type rules have changed:
// see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1048)
using F_Ret = std::decay_t<decltype(f(*begin(c)))>;
std::vector<F_Ret> res;
res.reserve(std::distance(begin(c), end(c)));
for (const auto& e : c)
{
res.push_back(f(e));
}
return res;
}
}
template <typename Container, typename F>
auto RetrieveTransformation(const Container& c, F f)
-> decltype(detail::RetrieveTransformation(c, f))
{
return detail::RetrieveTransformation(c, f);
}
And then use it as
std::vector<int> lv = RetrieveTransformation(la, std::mem_fn(&A::getColor));
// or
// auto lv = RetrieveTransformation(la, [](const A&a){return a.color;});
Live Demo

Related

Custom formatting of the elements of std::vectors using the fmt library

While I can use <fmt/ranges.h> to readily output the contents of a std::vector<T>, I'm at a loss to format the display of its elements according to my preferences.
#include <fmt/core.h>
#include <fmt/ranges.h>
int main() {
double x1 = 1.324353;
double x2 = 4.432345;
std::vector<double> v = {x1, x2};
fmt::print("{}\n", v); // OK [1.324353, 4.432345]
fmt::print("{:+5.2}\n", x1); // OK +1.3
// fmt::print("{:+5.2}\n", v); // Does not compile!
return EXIT_SUCCESS;
}
The program outputs:
[1.324353, 4.432345]
+1.3
but is missing the desired output from the commented out line in my code above
[ +1.3, +4.4]
I then tried implementing a custom formatter for vectors of ordinary type but my attempt comes up short:
// custom formatter for displaying vectors
template <typename T>
struct fmt::formatter<std::vector<T>> : fmt::formatter<T> {
constexpr auto parse(format_parse_context &ctx) {
return ctx.begin();
}
template <typename FormatContext>
auto format(std::vector<T> v, FormatContext &ctx) {
std::vector<std::string> v_str;
v_str.reserve(v.size());
const auto fmt_str = [&]() {
if constexpr (std::is_integral<T>::value) {
return "{:+5}";
} else if constexpr (std::is_floating_point<T>::value) {
return "{:+5.2}";
} else {
return "{}";
}
}();
for (auto &e : v) {
v_str.push_back(fmt::format(fmt_str, e));
}
return format_to(ctx.out(), "{}", v);
}
};
The compiler complains
type_traits:3174:38: error: ambiguous partial specializations of 'formatter<std::vector<double>>'
: public integral_constant<bool, __is_constructible(_Tp, _Args...)>
How do I get the fmt library to display the contents of a vector with custom formatting? The version I'm currently using is 8.1.1.
You can do it as follows:
std::vector<double> v = {1.324353, 4.432345};
fmt::print("{::+5.2}\n", v);
This prints:
[ +1.3, +4.4]
godbolt
Note the extra :. Format specifiers after the first colon (empty in this case) apply to the vector itself. Specifiers after the second colon (+5.2) apply to elements.

How to define lambda function in private?

I want to hide details of the lambda function into private part of a class.
I tried to separate the lambda function part from for_each() function.
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
class Sol
{
private:
vector<int> vec = vector<int>{ 1,2,3,4,5 };
int target = 10;
auto lambdaFunc = [=](int& v) { v += target; };
public:
void addConst() {
for_each(vec.begin(), vec.end(), lambdaFunc);
}
void printVec() {
for_each(vec.begin(), vec.end(), [](int v) {cout << v << endl; });
}
};
int main()
{
Sol sol;
sol.addConst();
sol.printVec();
return 0;
}
If I don't separate lambdaFunc from the for_each() function, I got elements of vector printed out.
However, by separating lambdaFunc, I got error message:
error: non-static data member declared 'auto'
Changing auto to static auto didn't solve.
If you have access to c++17 compiler, the best option is to provide a private member function as #VittorioRomeo shown in his answer(which is more straight forward IMO).
c++11 Solution!
Another way(s) is to provide the type for the lambda. You can
either use std::function with some type-erasure cost to define the
type of the lambda.
(See Live)
std::function<void(int&)> lambdaFunc = [=](int& v) { v += target; };
Or, if lambda can be changed to capture less one, that can be stored
into a typed function pointer like follows. In which target will
be passed as the second parameter of the lambda which made the lambda
capture-less. But that need also change of addConst() function.
(See Live)
class Sol
{
private:
std::vector<int> vec{ 1,2,3,4,5 };
// ^^^^^^^^^^^^^^ -> can use just braced-init-list
int target{ 10 };
void(*lambdaFunc)(int&, int) = [](int& v, int tar) { v += tar; };
//^^^^^^^^^^^^^^^^^^^^^^^^^ // fun-pointer type
public:
void addConst()
{
for (auto& element : vec) lambdaFunc(element, target);
}
};
Not sure why you would want to do this. If you really have a valid reason, you can use a private member function instead:
class Sol{
private:
auto lambdaFunc() { return [=](int& v) { v += target; }; }
public:
void addConst() {
for_each(vec.begin(), vec.end(), lambdaFunc());
}
};

Virtually turn vector of struct into vector of struct members

I have a function that takes a vector-like input. To simplify things, let's use this print_in_order function:
#include <iostream>
#include <vector>
template <typename vectorlike>
void print_in_order(std::vector<int> const & order,
vectorlike const & printme) {
for (int i : order)
std::cout << printme[i] << std::endl;
}
int main() {
std::vector<int> printme = {100, 200, 300};
std::vector<int> order = {2,0,1};
print_in_order(order, printme);
}
Now I have a vector<Elem> and want to print a single integer member, Elem.a, for each Elem in the vector. I could do this by creating a new vector<int> (copying a for all Elems) and pass this to the print function - however, I feel like there must be a way to pass a "virtual" vector that, when operator[] is used on it, returns this only the member a. Note that I don't want to change the print_in_order function to access the member, it should remain general.
Is this possible, maybe with a lambda expression?
Full code below.
#include <iostream>
#include <vector>
struct Elem {
int a,b;
Elem(int a, int b) : a(a),b(b) {}
};
template <typename vectorlike>
void print_in_order(std::vector<int> const & order,
vectorlike const & printme) {
for (int i : order)
std::cout << printme[i] << std::endl;
}
int main() {
std::vector<Elem> printme = {Elem(1,100), Elem(2,200), Elem(3,300)};
std::vector<int> order = {2,0,1};
// how to do this?
virtual_vector X(printme) // behaves like a std::vector<Elem.a>
print_in_order(order, X);
}
It's not really possible to directly do what you want. Instead you might want to take a hint from the standard algorithm library, for example std::for_each where you take an extra argument that is a function-like object that you call for each element. Then you could easily pass a lambda function that prints only the wanted element.
Perhaps something like
template<typename vectorlike, typename functionlike>
void print_in_order(std::vector<int> const & order,
vectorlike const & printme,
functionlike func) {
for (int i : order)
func(printme[i]);
}
Then call it like
print_in_order(order, printme, [](Elem const& elem) {
std::cout << elem.a;
});
Since C++ have function overloading you can still keep the old print_in_order function for plain vectors.
Using member pointers you can implement a proxy type that will allow you view a container of objects by substituting each object by one of it's members (see pointer to data member) or by one of it's getters (see pointer to member function). The first solution addresses only data members, the second accounts for both.
The container will necessarily need to know which container to use and which member to map, which will be provided at construction. The type of a pointer to member depends on the type of that member so it will have to be considered as an additional template argument.
template<class Container, class MemberPtr>
class virtual_vector
{
public:
virtual_vector(const Container & p_container, MemberPtr p_member_ptr) :
m_container(&p_container),
m_member(p_member_ptr)
{}
private:
const Container * m_container;
MemberPtr m_member;
};
Next, implement the operator[] operator, since you mentioned that it's how you wanted to access your elements. The syntax for dereferencing a member pointer can be surprising at first.
template<class Container, class MemberPtr>
class virtual_vector
{
public:
virtual_vector(const Container & p_container, MemberPtr p_member_ptr) :
m_container(&p_container),
m_member(p_member_ptr)
{}
// Dispatch to the right get method
auto operator[](const size_t p_index) const
{
return (*m_container)[p_index].*m_member;
}
private:
const Container * m_container;
MemberPtr m_member;
};
To use this implementation, you would write something like this :
int main() {
std::vector<Elem> printme = { Elem(1,100), Elem(2,200), Elem(3,300) };
std::vector<int> order = { 2,0,1 };
virtual_vector<decltype(printme), decltype(&Elem::a)> X(printme, &Elem::a);
print_in_order(order, X);
}
This is a bit cumbersome since there is no template argument deduction happening. So lets add a free function to deduce the template arguments.
template<class Container, class MemberPtr>
virtual_vector<Container, MemberPtr>
make_virtual_vector(const Container & p_container, MemberPtr p_member_ptr)
{
return{ p_container, p_member_ptr };
}
The usage becomes :
int main() {
std::vector<Elem> printme = { Elem(1,100), Elem(2,200), Elem(3,300) };
std::vector<int> order = { 2,0,1 };
auto X = make_virtual_vector(printme, &Elem::a);
print_in_order(order, X);
}
If you want to support member functions, it's a little bit more complicated. First, the syntax to dereference a data member pointer is slightly different from calling a function member pointer. You have to implement two versions of the operator[] and enable the correct one based on the member pointer type. Luckily the standard provides std::enable_if and std::is_member_function_pointer (both in the <type_trait> header) which allow us to do just that. The member function pointer requires you to specify the arguments to pass to the function (non in this case) and an extra set of parentheses around the expression that would evaluate to the function to call (everything before the list of arguments).
template<class Container, class MemberPtr>
class virtual_vector
{
public:
virtual_vector(const Container & p_container, MemberPtr p_member_ptr) :
m_container(&p_container),
m_member(p_member_ptr)
{}
// For mapping to a method
template<class T = MemberPtr>
auto operator[](std::enable_if_t<std::is_member_function_pointer<T>::value == true, const size_t> p_index) const
{
return ((*m_container)[p_index].*m_member)();
}
// For mapping to a member
template<class T = MemberPtr>
auto operator[](std::enable_if_t<std::is_member_function_pointer<T>::value == false, const size_t> p_index) const
{
return (*m_container)[p_index].*m_member;
}
private:
const Container * m_container;
MemberPtr m_member;
};
To test this, I've added a getter to the Elem class, for illustrative purposes.
struct Elem {
int a, b;
int foo() const { return a; }
Elem(int a, int b) : a(a), b(b) {}
};
And here is how it would be used :
int main() {
std::vector<Elem> printme = { Elem(1,100), Elem(2,200), Elem(3,300) };
std::vector<int> order = { 2,0,1 };
{ // print member
auto X = make_virtual_vector(printme, &Elem::a);
print_in_order(order, X);
}
{ // print method
auto X = make_virtual_vector(printme, &Elem::foo);
print_in_order(order, X);
}
}
You've got a choice of two data structures
struct Employee
{
std::string name;
double salary;
long payrollid;
};
std::vector<Employee> employees;
Or alternatively
struct Employees
{
std::vector<std::string> names;
std::vector<double> salaries;
std::vector<long> payrollids;
};
C++ is designed with the first option as the default. Other languages such as Javascript tend to encourage the second option.
If you want to find mean salary, option 2 is more convenient. If you want to sort the employees by salary, option 1 is easier to work with.
However you can use lamdas to partially interconvert between the two. The lambda is a trivial little function which takes an Employee and returns a salary for him - so effectively providing a flat vector of doubles we can take the mean of - or takes an index and an Employees and returns an employee, doing a little bit of trivial data reformatting.
template<class F>
struct index_fake_t{
F f;
decltype(auto) operator[](std::size_t i)const{
return f(i);
}
};
template<class F>
index_fake_t<F> index_fake( F f ){
return{std::move(f)};
}
template<class F>
auto reindexer(F f){
return [f=std::move(f)](auto&& v)mutable{
return index_fake([f=std::move(f),&v](auto i)->decltype(auto){
return v[f(i)];
});
};
}
template<class F>
auto indexer_mapper(F f){
return [f=std::move(f)](auto&& v)mutable{
return index_fake([f=std::move(f),&v](auto i)->decltype(auto){
return f(v[i]);
});
};
}
Now, print in order can be rewritten as:
template <typename vectorlike>
void print(vectorlike const & printme) {
for (auto&& x:printme)
std::cout << x << std::endl;
}
template <typename vectorlike>
void print_in_order(std::vector<int> const& reorder, vectorlike const & printme) {
print(reindexer([&](auto i){return reorder[i];})(printme));
}
and printing .a as:
print_in_order( reorder, indexer_mapper([](auto&&x){return x.a;})(printme) );
there may be some typos.

C++ Lambda Function for BFS Traversal

Using the two functions below, how could I use a lambda function to BFS Traverse through a Graph of Thing's called x
i.e. Graph<Thing> x
which involves sending the display function to the bfsTraverse function so that the information in each Thing can be displayed.
void display(const Thing& c)
{
cout<<left<<setw(3)<<c.getKey()<<" "<<left<<setw(2)<<c.getLabel()<<endl;
}
template <typename E>
void Graph<E>::bfsTraverse(FuncType func)
{
/* some code not necessary to describe */
}
So basically, I just need to understand how to use a lambda function to tie these together here.
It pretty straightforward. For example, let;s print values of vector using lambda:
#include <algorithm>
#include <vector>
#include <iostream>
int main (int argc, char* argv[]) {
std::vector <int> data{1,2,3,4};
std::for_each (data.begin (), data.end (), [] (const int val) { std::cout << val << std::endl;});
return 0;
}
last argument [] (...) is the lambda.
A function, which accepts lambdas, might look like this:
template <typename E, typename FuncType>
void Graph<E>::bfsTraverse (FuncType func)
{
/* some code not necessary to describe */
}
UPDATE
In case of a graph you should do the following. Your graph's implementation should have a method to access vertices: it might be 'getRoot', 'getSource', 'getAllNodes', it's implementation defined. I'll stick with 'getRoot'. Each vertex/node should have a method like 'getAdjacentVertices', 'getChildren', whatever. Combining all together:
template <typename E, typename FuncType>
void Graph<E>::bfsTraverse (FuncType func)
{
std::queue<Node> q;
auto&& root = getRoot ();
q.push (root);
while (not q.empty ()) {
auto&& current = q.front ();
q.pop ();
func (current);
auto&& adjacent = current.getAdjacent ();
for (auto&& a: adjacent) {
q.push (a);
}
}
Be aware, that I deliberately omit keeping list of visited nodes and other things. But idea itself stays the same. Now you can call this function as follows:
Graph<E> g;
g.bfsTraverse ( [] (const Node& n) {
std::cout << n.to_str () << std::endl;
}
);

How to apply a tuple of actions on tuple of numbers?

I have two tuples, one containing values and another tuple containing actions for these values.
Now I want to apply the corresponding action on each value, with as little code "overhead" as possible.
Something like the simplified example below.
#include <iostream>
#include <boost/hana.hpp>
namespace hana = boost::hana;
using namespace hana::literals;
struct ThinkPositive
{
void operator()(int &val) const
{
std::cout << "Think positive!\n";
val = std::abs(val);
}
};
struct Nice
{
void operator()(int &val) const
{
std::cout << val << " is nice!\n";
}
};
void numbers()
{
auto handlers = hana::make_tuple(Nice{}, ThinkPositive{});
auto nums = hana::make_tuple(5, -12);
auto handlers_and_nums = hana::zip(handlers, nums);
hana::for_each(handlers_and_nums, [](auto &handler_num) {
handler_num[0_c](handler_num[1_c]);
});
auto result = hana::transform(handlers_and_nums, [](const auto &handler_num) {
return handler_num[1_c];
});
hana::for_each(result, [](const auto num) {
std::cout << "got " << num << '\n';
});
}
int main()
{
numbers();
}
While the example above works it would be nicer to modify the contents of nums in place.
Is there a way to modify nums in place?
You could use zip_with, but it seems to be against its nature (it requires the function to actually return something, but your operators () return nothing:
auto special_compose = [](auto&& l, auto&& r){ l(r); return 0; };
hana::zip_with(special_compose, handlers, nums);
demo
If you can make your operators return something, you could go with lockstep:
hana::fuse(hana::fuse(hana::lockstep(hana::always(0)))(handlers))(nums);
demo
There should be something like lockstep defined without the outer f call, but I found nothing in the docs.
A little more standard solution (won't fit your requirement of as little code overhead as possible):
template<typename Fs, typename Params, size_t... is>
void apply_in_lockstep_impl(Fs&& fs, Params&& ps, std::index_sequence<is...>){
int x[] = { (fs[hana::integral_c<size_t,is>](ps[hana::integral_c<size_t,is>]),0)... };
}
template<typename Fs, typename Params>
void apply_in_lockstep(Fs&& fs, Params&& ps){
static_assert(hana::size(fs) == hana::size(ps), "");
apply_in_lockstep_impl(std::forward<Fs>(fs),
std::forward<Params>(ps),
std::make_index_sequence<decltype(hana::size(ps))::value>{});
}
but at the call site it is prettier:
apply_in_lockstep(handlers, nums);
demo
As was pointed in the comments another level of indirection can also help.
Here this would mean to transform the sequence into a sequence of pointer, via which the original values are modified.
auto nums_ptr = hana::transform(nums, [](auto &num) { return &num; });
auto handlers_and_nums = hana::zip(handlers, nums_ptr);
hana::for_each(handlers_and_nums, [](auto &handler_num) {
handler_num[0_c](*handler_num[1_c]);
});
demo
Another, more "traditional", way is to iterate over a range.
This would be like using an old for loop.
auto indices = hana::make_range(0_c, hana::length(handlers));
hana::for_each(indices, [&](auto i) {
handlers[i](nums[i]);
});
demo