Given a vector of objects, is there an elegant way to extract its member? I am currently just using a for loop but it would be nice if there is a way to do it. Example:
#include <vector>
struct Object {
int x;
float y;
};
int main() {
std::vector<Object> obj;
// Fill up obj
std::vector<int> all_x = obj.x; // Won't work obviously
}
With range-v3, it would simply be
std::vector<int> xs = objs | ranges::view::transform(&Object::x);
or just use the view:
auto xs = objs | ranges::view::transform(&Object::x);
Demo
As std::vector (or c++ in general) does not support covariant aggregation, there is no syntactically pretty way to do what you want.
If you really want to initialize all_x with x members of obj elements, then you can define a new iterator class, like that:
class getx_iter : public vector<Object>::iterator
{
public:
getx_iter(const vector<Object>::iterator &iter) : vector<Object>::iterator(iter) {}
int operator*() { return (*this)->x; }
};
Working code example
If you're okay with initializing an empty vector and then filling it, std::transform with a labmda is a clearer option (as #andars suggested).
You could also avoid extra initialization by using vector::reserve() and back_inserter:
xs.reserve(foos.size());
std::transform(foos.begin(), foos.end(), back_inserter(xs), [](Foo f){return f.x;});
Also notice that while x is a private member of Object and has no getters, it will be quite hard to extract it.
I can't think of a really good way.
One alternative would be to use std::transform with a lambda.
#include <vector>
#include <algorithm>
class Foo {
public:
Foo(int x_): x(x_) {}
int x;
};
int main() {
std::vector<Foo> foos;
for (int i = 0; i<10; i++) {
foos.push_back(Foo(i));
}
std::vector<int> xs;
xs.resize(foos.size());
std::transform(foos.begin(), foos.end(), xs.begin(), [](Foo f){return f.x;});
}
Some template and macro magic, and it works:
#include <vector>
#include <algorithm>
using namespace std;
class Foo {
public:
Foo(int x_): x(x_) {}
int x;
};
#define GETFIELD(type, field) [](const type & obj){return obj.field;}
template<typename T,typename U, typename TMapper>
void MapVector(vector<T>& src, vector<U>& dst, TMapper mapper) {
for (const auto& it: src) {
dst.push_back(mapper(it));
}
}
#define MapVectorField(src, dst, field) MapVector(src, dst, GETFIELD(decltype(src)::value_type, field))
int main() {
vector<Foo> vFoo;
for (int i = 0; i < 10; i++) {
vFoo.push_back(Foo(i));
}
vector<int> vX;
MapVector(vFoo, vX, GETFIELD(Foo, x));
MapVectorField(vFoo, vX, x);
for (int i = 0; i < vX.size(); i++) {
printf("%d\n", vX[i]);
}
}
Of course, remember that it is not very good to name macro MapVectorField as it is function, or write using namespace std in production.
Here's another macro that's pretty easy to use. It does require the programmer to know that the internal loop variable name is "e", for element. If you keep that in mind, it will work for both fields or methods, and also for normal objects or pointers to objects.
The macro is simply:
#define map(vTarget, vSource, eField) \
for (auto e: vSource) { vTarget.push_back(eField); }
For example, suppose we have a class named Person which has a string name field and an int age field, and we want to extract just the names into a new vector. An example usage might then be:
map(names, people, e.name);
Note the "e" in the third parameter. This is required because the macro uses the variable "e" to iterator over the elements in the vector. So keep in mind which syntax you need to use. I believe these are the 4 cases:
e.field
e.method()
e->field
e->method()
Let's try them out. Here's a full example. Hey, if anyone has a more elegant join solution, I'm all ears.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#define map(vTarget, vSource, eField) \
for (auto e: vSource) { vTarget.push_back(eField); }
class Person {
public:
string name;
int age;
public:
Person(string name, int age) {
this->name=name;
this->age=age;
}
string& getName() {return name;}
int getAge() {return age;}
};
string join(vector<string> vSource, const string separator) {
string buf;
bool first=true;
for (string e: vSource) {
if (first) {
first=false;
} else {
buf+=separator;
}
buf+=e;
}
return buf;
}
int main(int argc, char **argv) {
// using a normal Object
vector<Person> people;
vector<string> names;
people.push_back(Person("john", 27));
people.push_back(Person("jane", 26));
names.clear();
map(names, people, e.name);
cout << join(names, ",") << endl;
names.clear();
map(names, people, e.getName());
cout << join(names, ",") << endl;
// using a pointer to an object
vector<Person*> morePeople;
morePeople.push_back(new Person("bob", 27));
morePeople.push_back(new Person("amy", 26));
names.clear();
map(names, morePeople, e->name);
cout << join(names, ",") << endl;
names.clear();
map(names, morePeople, e->getName());
cout << join(names, ",") << endl;
}
Sample output:
john,jane
john,jane
bob,amy
bob,amy
Related
I have a structure that in its constructor receives an initialization list std::initializer_list<P...> of type parameter pack. That constructor is filled with lambda functions, and they are saved in a std::vector<P...>.
How can I get the return of those functions when traversing the vector calling each function?
Here is an example of the structure and what I want to do:
#include <iostream>
#include <functional>
#include <initializer_list>
using namespace std;
struct my_type {
my_type(){}
my_type(string _value) : value(_value) {}
string value = "test";
string getValue(){return value;}
};
template<typename A, class...P>
struct struct_name {
struct_name(std::initializer_list<P...> list) : functions(list) {}
std::vector<P...> functions;
string value;
my_type type;
string execute_functions(){
for (size_t i = 0; i < functions.size(); i++)
{
value = functions[i](type); // something like this, this does not work
}
return value;
std::cout << value;
}
};
typedef struct_name<std::function<void(my_type)>, std::function<void(my_type)>> _functions;
int main(int argc, char const *argv[])
{
_functions object = {
[](my_type var)->string{
return var.getValue();
},
[](my_type var)->string{
return var.getValue();
},
};
return 0;
}
Everything works perfect except the way to obtain those values. I don't know how, and no matter how hard I look I can't find answers.
EDIT: I can't paste the complete code, because it depends on many other classes. I tried to recreate that section, the type is a parameter pack because it receives multiple types besides lambdas, but in the example I just put it that way.
If you are trying to process a value through a series of function you can just use std::accumulate:
#include <iostream>
#include <vector>
#include <functional>
#include <numeric>
int main()
{
std::vector<std::function<float(float)>> functions = {
[] (float f) { return f*f; },
[] (float f) { return f + 2; }
};
float result = std::accumulate(functions.begin(), functions.end(), 1.5f,
[] (float v, const auto& lambda) {
return lambda(v);
}
);
std::cout << 1.5f << " -> " << result << std::endl;
return 0;
}
But a vector can only contain one specified type, so what you are trying to do with you parameter pack P... doesn't make much sense, if you want to process multiple values through multiple functions with different signatures you'd better try with something like std::tuple<std::function<T1(T2)>, std::function<T3(T4)>, ...> and pass multiple values to it.
You should be using std::tuple, if you want to store arbitrary callable objects.
You can combine std::index_sequence with a fold expression for calling the functions:
#include <iostream>
#include <string>
#include <tuple>
#include <utility>
using std::string;
struct my_type {
my_type(){}
my_type(string _value) : value(_value) {}
string value = "test";
string getValue(){return value;}
};
template<class...P>
struct struct_name {
struct_name(P... args)
: functions(args...)
{}
std::tuple<P...> functions;
std::string value;
my_type type;
std::string execute_functions() {
return execute_helper(std::make_index_sequence<sizeof...(P)>{});
}
private:
template<size_t ...Is>
std::string execute_helper(std::index_sequence<Is...>)
{
((value += std::get<Is>(functions)(type)), ...);
return value;
}
};
int main()
{
struct_name foo(
[](my_type var)->string {
return var.getValue();
},
[](my_type var)->string {
return var.getValue();
});
std::cout << foo.execute_functions() << '\n';
return 0;
}
Consider a class whose default constructor takes in the file path as a parameter.
class Test
{
public:
Test(const std::string& filepath);
...
...
};
Now I wish to create and initialize an array of Test objects using unique pointers in VS2017.
int main()
{
std::unique_ptr<Test[]> m_Tests;
int testCount = 2;
std::string path1, path2;
m_Tests = std::make_unique<Test[]>(testCount); // This line gives a compilation error
m_Tests[0] = std::make_unique<Test>(path1);
m_Tests[1] = std::make_unique<Test>(path2);
}
How can I make this work?
g++ 9.2.0 tells me that you lack default constructor, i.e. one without parameters. Adding such constructor works fine. If it's not what you want, you can create array of unique_ptr's, so std::unique_ptr<std::unique_ptr<Test>[]> and after that initialize each element by hand, something similar to this:
#include <memory>
#include <algorithm>
#include <iostream>
struct Test {
std::string str_;
Test(std::string const& str) : str_(str) { }
void print() { std::cout << str_ << '\n'; }
};
int main()
{
std::unique_ptr<std::unique_ptr<Test>[]> m_Tests;
int testCount = 2;
std::string path1{"a"}, path2{"b"};
m_Tests = std::make_unique<std::unique_ptr<Test>[]>(testCount);
std::array<std::string, 2> paths{path1, path2};
std::transform(paths.begin(), paths.end(), &m_Tests[0],
[](auto const& p) { return std::make_unique<Test>(p); });
for (int i = 0 ; i < testCount ; ++i) {
m_Tests[i]->print();
}
}
There is no overload of std::make_unique that does this, so you would need to use new directly:
m_Tests.reset(new Test[testCount]{path1, path2});
This will however only compile if testCount is a constant expression, so you need to change the definition int testCount = 2; to const int or constexpr int.
If testCount is not a constant expression, there needs to be a default constructor defined for the case that testCount is smaller than 2 at runtime.
So, really, you probably want to ignore testCount and just let the array size be deduced:
m_Tests.reset(new Test[]{path1, path2});
It would be much easier if you just used std::vector:
std::vector<Test> m_Tests;
//...
m_Tests.emplace_back(path1);
m_Tests.emplace_back(path2);
How about you use std::array and can you get rid of testCount (or use it as constexp) then the code can be like below.
class Test
{
public:
Test(const std::string& filepath){}
};
int main()
{
constexpr int testCount = 2;
std::unique_ptr<std::array<Test, testCount>> m_Tests;
std::string path1, path2;
m_Tests = std::make_unique<std::array<Test, testCount>>(std::array<Test, testCount>{path1,path2});
}
I have a class A with a member vector<class B>. I would like to loop through this vector from outside class A in a clean way. I need to do operations on B using its public functions.
To do so, I thought of having a function int get_next_element(B * in_B), where I can return 0 if I have correctly loaded the next element and -1 otherwise.
I thought of doing this by using an iterator, but I found two issues with this. First of all, I wasn't able to find a neat way to convert an iterator to a pointer (it seems I could use an iterator just like a pointer, but I'm unsure that's a good solution). Secondly, I would need to check if there's a value referenced by my iterator, and since the closest thing to a "null iterator" is the .end() element I can't figure out how I would then initialise it. If I initialise it (empty) and have the reference .end(), it wont refer to anything comparable if I add something to it.
I could have an extra int that keeps track of which element I'm at, but then I'd have to manage that int whenever I add elements, etc.
I considered placing the iteration code outside of class A, but I may need to change or access individual elements during the loop, so that would make a complex/big iteration block.
How would I solve this problem in a clean way (such as int get_next_element(B * in_b))?
EDIT:
Here's some code:
Header:
class B {
public:
B();
void set_size(int in_size);
int get_size();
protected:
int mSize;
};
class A {
public:
A();
void add_B(B in_B);
int get_next_element(B * in_B);
protected:
std::vector<B> mObjects;
};
cpp file:
B::B() {
// Stuff
}
void B::set_size(int in_size) {
mSize = in_size;
}
int B::get_size() {
return mSize;
}
A::A() {
// Stuff
}
void A::add_B(B in_B) {
mObjects.push_back(in_B);
}
int A::get_next_element(B * in_B) {
// ToDo : handle elements
}
And main:
int main() {
A test_a;
for (int i = 0; i < 5; i++) {
B tmp_b;
tmp_b.set_size(i);
test_a.add_B(tmp_b);
}
B iterator_b;
while (0 == get_next_element(& iterator_b)) {
if (iterator_b.get_size > 2) {
B tmp_b;
tmp_b.set_size(iterator_b.get_size - 2);
test_a.add_B(tmp_b);
iterator_b.set_size(2);
}
}
}
So, basically A holds a bunch of Bs and can help the main iterate through them and (in this example) cut them into smaller pieces while not having too much code in the main. There's quite a few dimensions/ways this will be done, which is partially why I'd like to "hide" as much of the code in A.
(This is a bit simplified, like the Bs may have to have internal relations, but basically that's the idea)
Consider using a range-base for loop (C++1x).
class A {
private:
std::vector<class B> vec;
public:
std::vector<class B>& get_vec() { return vec; }
};
A a_instance;
for (B &b : a_instance.get_vec()) {
b.print();
std::cout << "b = " << b << std::endl;
std::cout << "&b = " << &b << std::endl;
}
This, unfortunately, does not allow looking ahead, unless you keep track of index yourself.
this is what I mean...
#include <iostream>
#include <vector>
class B {
public:
B(int in) :mSize(in) {}
size_t mSize;
void set_size(int in_size) { mSize = in_size;}
int get_size() {return mSize;}
};
class A {
using container = std::vector<B>;
using iterator = container::iterator;
container mObjects;
public:
void add_B(B in_B) { mObjects.push_back(in_B); }
iterator begin() { return mObjects.begin(); }
iterator end() { return mObjects.end(); }
};
int main() {
A test_a;
for (int i = 0; i < 5; i++) {
test_a.add_B(B(i));
}
for( auto& item : test_a)
if (item.get_size() > 2) {
B tmp_b(item.get_size() - 2);
item.set_size(2);
test_a.add_B(tmp_b);
break;//if using a vector, must break as vector can change/reallocate on 'add_B()'
}
}
I've been trying for the last three day to figure out how to implement a generic way of getting the value out of a boost::variant<...>, but it's been quite difficult.
Here is the solution I could come up with, which it not at all generic:
#include <iostream>
#include "boost\variant\variant.hpp"
using MyVariant = boost::variant<int, std::string>;
class VariantConverter : public boost::static_visitor<>
{
private:
mutable int _int;
mutable std::string _string;
static VariantConverter apply(MyVariant& v)
{
VariantConverter res;
v.apply_visitor(res);
return res; // copy will be elided, right?
}
public:
void operator()(int& i) const
{
_int = i;
}
void operator() (std::string& s) const
{
_string = s;
}
static int to_int(MyVariant v)
{
return apply(v).from_int();
}
static std::string to_string(MyVariant v)
{
return apply(v).from_string();
}
int from_int()
{
return _int;
};
std::string from_string()
{
return _string;
};
};
int main()
{
using namespace std;
MyVariant v = 23;
int i = VariantConverter::to_int(v);
cout << i << endl;
v = "Michael Jordan";
std::string s = VariantConverter::to_string(v);
cout << s.c_str() << endl;
cin.get();
return 0;
}
I'd appreciate it if someone could guide me towards a better solution.
Or perhaps someone could explain to me the rationale behind this:
if I declare a:
using MyVariant = boost::variant<int, std::string>;
and then a:
ConverterToInt : basic_visitor<int> {
public:
int operator() (int i) { return i; };
};
Why is it that when I try to apply the ConverterToInt to a MyVariant as such:
ConverterToInt cti;
MyVariant i = 10;
i.apply_visitor(cti);
I get a compiler error about trying to find a operator() that takes a std::string?
It seems to me that apply_visitor is trying to call an operator() for each of the types MyVariant can take. Is that so? If it is, why? How can i avoid this behavior?
Cheers!
You can avoid the error message by telling ConverterToInt what to do with a std::string. You might know that i can't be a std::string but it's unreasonable to expect the compiler to know that (and if it is true, why are you using a variant?).
apply_visitor will only call the correct operator() method, but it decides at run time, and the compiler needs to have all the possibilities covered to generate the code.
MyVariant iv = 10;
int i = boost::get<int>(iv);
boost::variant does not "call" each operator() of an interface when invoked, but it must be able to. That's the entire point. A variant can hold any of the template types, so if you want to define an operation on it, you must specify somewhere what that operation means for each type.
Right now I have a switch statement that takes in an input and choose one of the following actions:
Option 1
for(; i < queue_size; ++i)
{
prepared->setString(i+1, queue.at(i).model);
}
Option 2
for(; i < queue_size; ++i)
{
prepared->setString(i+1, queue.at(i).manufacturer);
}
Option 3
for(; i < queue_size; ++i)
{
prepared->setString(i+1, queue.at(i).name);
}
In PHP, you would be able to do the same doing something like this:
$queue[i][$member];
$member could then be set to "name", "manufacturer", etc.
Is there any way to do something similar or more robust in C++?
Thanks in advance for any help/suggestions!
Using C++11 std::function or boost::function if you don't have C++11:
std::map<YourSwitchType, std::function<void(void)> functionMap;
then define functions such as
void manufacturString() {
for(; i < queue_size; ++i) {
prepared->setString(i+1, queue.at(i).manufacturer);
}
}
for each case, and populate the map with these.
functionMap[someSwitchValue] = std::bind(&ThisType::manufactureString, this);
Then you can just call them:
functionMap[someSwitchValue]();
One advantage of this approach is that it doesn't limit you to member functions. You can put non-member functions, functors, static member and non-member functions in the same map. The only limitation is that after binding, they return void and take no arguments (that is specific to this example).
You could do this with a map from your property names to pointer-to-member. But it's a bit of work (you need to create that mapping yourself), and the syntax gets a bit hairy. (And all the members you want to address this way must be of the same type.)
Demo:
#include <iostream>
#include <map>
struct Foo {
std::string name;
std::string address;
};
typedef std::string Foo::* FooMemPtr;
typedef std::map<std::string, FooMemPtr> propmap;
int main()
{
propmap props;
props["name"] = &Foo::name;
props["address"] = &Foo::address;
/* ... */
Foo myfoo;
myfoo.*(props["name"]) = "myname";
myfoo.*(props["address"]) = "myaddress";
std::cout << myfoo.*(props["address"]) << std::endl;
std::cout << myfoo.*(props["name"]) << std::endl;
}
If you can use enums instead of strings, then you can access name, manufacturer, etc. indexed off of the enum values. It depends on how dynamic you need to be.
Use the STL map to perform this. It works as you would do in PHP.
One option is to pass an extractor functor to the function:
#include <string>
#include <vector>
#include <boost/bind.hpp>
struct Some {
std::string model, manufacturer, name;
};
struct Prepared {
void setString(size_t, std::string const&);
};
template<class Extractor>
void foo(Extractor extract) {
Prepared* prepared = 0;
std::vector<Some> queue;
size_t i, queue_size = queue.size();
for(; i < queue_size; ++i) {
prepared->setString(i+1, extract(queue.at(i)));
}
}
int main() {
// C++03
foo(boost::bind(&Some::model, _1));
foo(boost::bind(&Some::manufacturer, _1));
foo(boost::bind(&Some::name, _1));
// C++11
foo([](Some const& some){ return some.model; });
foo([](Some const& some){ return some.manufacturer; });
foo([](Some const& some){ return some.name; });
}
You can do this type of thing using member variable points (there are also member function pointers). The boost bind functions are more generic, but this is ultimately what they are doing underneath (at least in this scenario).
#include <iostream>
#include <string>
struct item
{
std::string a, b;
};
//the really ugly syntax for a pointer-to-member-variable
typedef std::string item::*mem_str;
//show each member variable from the list
void show_test( item * objs, size_t len, mem_str var )
{
for( size_t i=0; i < len; ++i )
std::cout << objs[i].*var << std::endl;
}
int main()
{
//create some test data
item test[2];
test[0].a = "A-Zero";
test[0].b = "B-Zero";
test[1].a = "A-One";
test[1].b = "B-One";
//show variables
show_test( test, 2, &item::a );
show_test( test, 2, &item::b );
return 0;
}