class constructor initalization with a map second argument - c++

I got a map like
typedef float(*function)(vector<int>);
map < string, function> mymap{
{ "maximum", &maxValue },
{ "minimum", &minValue },
{... , ...},
};
and got the definitions for functions that I used in the map as
float maxValue(vector<int> v){
auto cit = max_element(v.begin(), v.end());
return *cit;
}
and a similar function definitions for other functions that I used in the above map definition.
I got a class with two private data variables in a .h file as "string value;" and "float aggregate"
Now, my question is I want to define a constructor for this class and initialize the object's member data in.cpp file with values as
// aggregates is my class name
aggregates::aggregates(string val, const vector<int>& v): value(val), aggregate(.....)//here is my problem how can I initialize aggregate from the map that I mentioned above.
Thanks in advance

class aggregates
{
private:
float aggregate;
string value;
public:
aggregates(const string & val, const vector<int> & v, const map <string, function> & mymap) : value(val)
{
aggregate = mymap.at(value)(v); // instead of mymap[value](v), due to const&
}
};

Related

Initialize members of a class in C++

I have a class with the following declaration:
class OrderBook {
std::string OrderBookType;
std::map<double, vector<float*>> OrderBookData;
std::unordered_map<int, float*> OrderPool;
public:
OrderBook(string);
}
I have 2 questions regarding the class initialization:
I would like to specify the comparator for the OrderBook map based on OrderBookType.
Is the following valid/good programming practice?
OrderBook::OrderBook(string bookType) {
OrderBookType = bookType;
if (bookType == 'B') {
OrderBookData = std::map<float, vector<float*>, std::greater<float>>
}
else {
OrderBookData = std::map<float, vector<float*>, std::less<float>>
}
OrderPool;
}
How do I initialize an empty map for OrderPool? To make sure OrderPool is an empty unordered map, do I have to do the following:
OrderPool = std::unordered_map<int, float*>()
or is OrderPool; sufficient?
To 1.
No, it's not valid.
The types
std::map<float, vector<float*>, std::greater<float>>
and
std::map<float, vector<float*>, std::less<float>>
are different. You can't change the types at runtime.
IMHO the best approach is to create an own comparator that expects an argument and is passed to the constructor of the map (as mentionend in the comments of the question).
class Comp {
public:
Comp(bool greater) : g(greater) {}
bool operator()(double lhs, double rhs) const {
if (g) return lhs > rhs;
return lhs < rhs;
}
private:
bool g;
};
struct OrderBook {
std::string OrderBookType;
std::map<double, std::vector<float*>, Comp> OrderBookData;
std::unordered_map<int, float*> OrderPool;
public:
OrderBook(const std::string &);
};
OrderBook::OrderBook(const std::string &bookType) : OrderBookType(bookType), OrderBookData(Comp(bookType == "B")) {}
To 2.
std::unordered_map<int, float*> OrderPool; will be initialized as empty unordered map. The line
OrderPool;
does nothing.
You don't need to (and technically speaking you can't) initialize it again. If you want to clear the map you can use std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::clear
You could also create a new object and assign it with
OrderPool = std::unordered_map<int, float*>()
but I prefer
OrderPool.clear();

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.

Sort Over Different Class Members

I have a class that includes several members of type double.
Suppose I need to make a function that re-orders a vector of class objects based on the values of one of the members on the class. So:
class myClass{
...
public:
double x, y, z;
...
}
void SpecialSort_x(std::vector<myClass>& vec) {
// re-order stuff according to values of vec[i].x
...
}
But now, I want to be able to do the same re-ordering, but according to values of the other members of the class (y and z in the code above).
Instead of making two more functions that are identical to the first one, except with all references to x changed to y or z, I would like to make a single polymorphic function that can re-order the vector according to any of the members of myClass.
What is the best way to do this?
You can use std::sort, combined with a lambda and a pointer to member thus:
#include <vector>
#include <algorithm>
class MyClass
{
public:
double x, y, z;
};
typedef double MyClass::* Field;
void specialSort(std::vector<MyClass>& vec, Field field)
{
std::sort(vec.begin(), vec.end(), [field](const MyClass & a, const MyClass & b) -> bool
{
return a.*field < b.*field;
});
}
int main()
{
std::vector<MyClass> vec;
Field member = &MyClass::x;
specialSort(vec, member);
return 0;
}
And you could also templatise the sort using:
template<class T>
void specialSort(std::vector<T>& vec, double T::* field)
{
std::sort(vec.begin(), vec.end(), [field](const T& a, const T& b) -> bool
{
return a.*field < b.*field;
});
}
I agree with everyone suggesting alternate approaches given the problem description here.
However, if you ever really have the need to access a class member chosen at runtime, you can use a pointer-to-member type. There is usually a more elegant way to accomplish the effect you want, though.
For example:
#include <iostream>
#include <vector>
struct X {
double a;
double b;
double c;
};
void operate_on_member(const X& x, double X::*pm)
{
std::cout << x.*pm << '\n';
}
int main()
{
std::vector<X> xs {
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
for (const auto& x : xs)
operate_on_member(x, &X::a);
for (const auto& x : xs)
operate_on_member(x, &X::b);
for (const auto& x : xs)
operate_on_member(x, &X::c);
}

How to make aliases of member function or variable of specific class(like an STL container)

When using a std::pair or std::map, we need to use "first" or "second" to access data. But the two variable name do not have clear meanings of what it really store for other co-workers that did not write this code. So if we can make aliases for "first" or "second", it would enhance much readability.
For example, the following code
static const std::map<std::string, std::pair<std::string, PFConvert>> COMM_MAP =
{ // keyword-> (caption, function)
{std::string("1"), {std::string("Big5 to Utf16LE"), &FileConvert_Big5ToUtf16LE}},
{std::string("2"), {std::string("Utf16LE to Utf8"), &FileConvert_Utf16LEToUtf8}},
{std::string("3"), {std::string("Utf8 to Big5"), &FileConvert_Utf8ToBig5}}
};
auto iterToExe = COMM_MAP.find(strTransType);
iterToExe->second.second();
The iterToExe->second.second(); has a truly bad readability.
So I try to use inherit to give aliases as following
template<typename PFComm>
class CCommContent : public std::pair<std::string, PFComm>
{
public:
std::string &strCaption = std::pair<std::string, PFComm>::first;
PFComm &pfComm = std::pair<std::string, PFComm>::second;
};
template<typename PFComm>
class CCommPair : public std::pair<std::string, CCommContent<PFComm>>
{
public:
std::string &strPattern = std::pair<std::string, CCommContent<PFComm>>::first;
CCommContent<PFComm> commContent = std::pair<std::string,CCommContent<PFComm>>::second;
};
template<typename PFComm>
class CCommMap : public std::map<std::string, CCommContent<PFComm>, std::less<std::string>, std::allocator<CCommPair<PFComm>>>
{};
But this comes to an another issue: I have to declare all the ctors, though i could call the base ctors, but it still not seems to be a smart method. I Just want to make aliases.
A simple way is to use macro ...... but it bypass the type checking. when using a nested structure, it may be a nightmare when debug.
Any advice or discussion would be appreciated.
Why not simply use your own struct with your own element names?
struct MyPair {
std::string strCaption;
PFComm pfComm;
};
With C++11 you can easily create new objects of it:
MyPair{std::string("Big5 to Utf16LE"), &FileConvert_Big5ToUtf16LE}}
And if you define your own operator<, you can have std::set work as a map:
bool operator<(const MyPair& a, const MyPair& b) {
return a.strCaption < b.strCaption;
}
typedef std::set<MyPair> MyPairMap;
Naturally, you can nest your custom structs to form more complex nested pairs, although in your case you might want to consider a flat triplet instead:
struct CommMapEntry {
std::string number;
std::string caption;
PFComm pfComm;
};
bool operator<(const MyPair& a, const MyPair& b) {
return a.number<b.number;
}
static const std::set<CommMapEntry> COMM_MAP;
How about some typedefs and accessor functions?
using CommEntry = std::pair<std::string, PFConvert>;
std::string const & getCaption(CommEntry const & e) { return e.first; }
PFConvert const & getFunction(CommEntry const & e) { return e.second; }
Now you can say:
auto it = COMM_MAP.find(strTransType);
if (it != COMM_MAP.end())
{
auto & c = getCaption(it->second);
auto & l = getLabel(it->second);
// ...
}
If you later change the details of the type, you just have adapt the accessor functions.
well, in c++11, we can using base::base in a derive class to use the base ctors. But note that vs2013 DO NOT compliant this. g++4.8 do.

How do I initialize a std::set comparator?

I need to initialize some comparator of the new data type TType based on std::set with some object o of another class Object:
typedef std::set <unsigned int, sortSet(o)> TType
This declaration is otside the class (in header file). At the time of the declaration this object does not have to exist, it will be created later.
class sortSet
{
private:
Object o;
public:
sortSet(Object &oo): o(oo) {}
bool operator() ( const unsigned int &i1, const unsigned int &i2 ) const
{
//Some code...
}
};
If the declaration was inside some method (when object has already been created), situation would be quite simple... What can I do?
The template parameter needs to be the type of the comparator, not a specific object of that type; you can provide a specific comparator object to be used in the std::set constructor:
typedef std::set<unsigned int, sortSet> TType;
Object o;
TType mySet(sortSet(o));
I am not sure if I understood your actual question, however, the general idiom to use a custom comparator is shown in the following contrived example.
#include <set>
class foo {
public:
int i_;
};
struct foo_comparator {
bool operator()( foo const & lhs, foo const & rhs ) {
return lhs.i_ < rhs.i_;
}
};
typedef std::set< foo, foo_comparator > foo_set;
int main() {
foo_set my_foo_set;
}