Mapping combination of 4 integers to a single value - c++

I have 4 separate integers that need to be mapped to an arbitrary, constant value.
For example, 4,2,1,1 will map to the number 42
And the number 4,2,1,2 will map to the number 86.
Is there anyway I can achieve this by using #define's or some sort of std::map. The concept seems very simple but for some reason I can't think of a good, efficient method of doing it. The methods I have tried are not working so I'm looking for some guidence on implementation of this.

Will a simple function suffice?
int get_magic_number( int a, int b , int c, int d)
{
if( (a==4)&&(b==2)&&(c==1)&&(d==1) ) return 42;
if( (a==4)&&(b==2)&&(c==1)&&(d==2) ) return 86;
...
throw SomeKindOfError();
}
Now that may look ugly, but you can easily create a macro to pretty it up. (Or a helper class or whatever... I'll just show the macro as I think its easy.
int get_magic_number( int a, int b , int c, int d)
{
#DEFINE MAGIC(A,B,C,D,X) if((a==(A))&&(b==(B))&&(c==(C))&&(d==(D))) return (X);
MAGIC(4,2,1,1, 42);
MAGIC(4,2,1,2, 86);
...
#UNDEF MAGIC
throw SomeKindOfError();
}
If you really care you can probably craft a constexpr version of this too, which you'll never be able to do with std::map based solutions.

Utilize a std::map<std::vector<int>, int>, so that the vector containing {4,2,1,1} will have the value 42, and so on.
Edit: I agree std::tuple would be a better way to go if you have a compiler with C++11 support. I used a std::vector because it is arguably more portable at this stage. You could also use a std::array<int, 4>.

If you do not have access to boost::tuple, std::tuple or std::array, you can implement a type holding 4 integers with a suitable less-than comparison satisfying strict weak ordering:
struct FourInts {
int a,b,c,d;
FourInts() : a(), b(), c(), d() {}
bool operator<(const FourInts& rhs) const {
// implement less-than comparison here
}
};
then use an std::map:
std::map<FourInts, int> m;
If you organise your ints in an array of standard library container, you can use std::lexicographical_compare for the less-than comparison.

If you know there's always 4 integers mapped to 1 integer I suggest you go with:
std::map< boost::tuple<int, int, int, int>, int >
Comparison (lexicographical) is already defined for tuples.

Related

Fast way to do lexicographical comparing 2 numbers

I'm trying to sort a vector of unsigned int in lexicographical order.
The std::lexicographical_compare function only supports iterators so I'm not sure how to compare two numbers.
This is the code I'm trying to use:
std::sort(myVector->begin(),myVector->end(), [](const unsigned int& x, const unsigned int& y){
std::vector<unsigned int> tmp1(x);
std::vector<unsigned int> tmp2(y);
return lexicographical_compare(tmp1.begin(),tmp1.end(),tmp2.begin(),tmp2.end());
} );
C++11 introduces std::to_string
You can use from to_string as below:
std::sort(myVector->begin(),myVector->end(), [](const unsigned int& x, const unsigned int& y){
std::string tmp1 = std::to_string(x);
std::string tmp2 = std::to_string(y);
return lexicographical_compare(tmp1.begin(),tmp1.end(),tmp2.begin(),tmp2.end());
} );
I assume you have some good reasons, but allow me to ask: Why are you sorting two int's by using the std::lexicographical order? In which scenario is 0 not less than 1, for example?
I suggest for comparing the scalars you want to use std::less . Same as std lib itself does.
Your code (from the question) might contain a lambda that will use std::less and that will work perfectly. But let us go one step further and deliver some reusable code ready for pasting into your code. Here is one example:
/// sort a range in place
template< typename T>
inline void dbj_sort( T & range_ )
{
// the type of elements range contains
using ET = typename T::value_type;
// use of the std::less type
using LT = std::less<ET>;
// make its instance whose 'operator ()'
// we will use
LT less{};
std::sort(
range_.begin(),
range_.end(),
[&]( const ET & a, const ET & b) {
return less(a, b);
});
}
The above is using std::less<> internally. And it will sort anything that has begin() and end() and public type of the elements it contains. In other words implementation of the range concept.
Example usage:
std::vector<int> iv_ = { 13, 42, 2 };
dbj_sort(iv_);
std::array<int,3> ia_ = { 13, 42, 2 };
dbj_sort(ia_);
std:: generics in action ...
Why is std::less working here? Among other obvious things, because it compares two scalars. std::lexicographical_compare compares two ordinals.
std::lexicographical_compare might be used two compare two vectors, not two elements from one vector containing scalars.
HTH

how to stop automatic conversion from int to float and vice-versa in std::map

I wrote a small program of using std::map here as follows.
int main()
{
map<int,float>m1;
m1.insert(pair<int,float>(10,15.0)); //step-1
m1.insert(pair<float,int>(12.0,13)); //step-2
cout<<"map size="<<m1.size()<<endl; //step -3
I created a map with int type as key and float type as value(key-value) pair for the map m1
Created a normal int-float pair and inserted to map.
Created a cross float-int pair and inserted to map. Now I know that implicit conversion is making this pair to get inserted to map.
Here I just don't want the implicit conversion to take place and compiler error should be given.
What sort of changes I have to do in this program/map to make the comipiler flag an error while we try to do step-2 type operation?
Here's a suggestion:
template <typename K, typename V, typename W>
void map_insert(map<K,V>& m, K k, W w) {
V v = w;
m.insert(pair<K,V>(k,v));
}
int main() {
map<int,float>m1;
map_insert(m1, 10, 15.0);
map_insert(m1, 12.0, 13); // compiler complains here
cout<<"map size="<<m1.size()<<endl;
The third template parameter is a bit awkward but is necessary to allow casting from double to float.
This is not possible (and even if it is possible, then it would be major hack that you shouldn't use).
insert takes a value_type as argument, which is a pair<int const,float>.
So, when you try to insert a pair<float, int>, the compiler looks for a conversion, that is: a constructor of pair<int const, float> that takes a pair<float, int> as argument, which simply exists. In fact, I tried to come up with a partial specialization for that template member (that allows the conversion) which then you could have fail on the remaining template parameter, but I failed to do so; it seems not possible. Anyway, it would be a very dirty hack that you just shouldn't be doing just to avoid a typo. Elsewhere you might need this conversion, and it's a no no to define anything in namespace std anyway.
So what is the solution to "How can I avoid this kind of typos?" ?
Here is what I usually do:
1) All my maps have a typedef for their type.
2) I then use ::value_type (and ::iterator etc) on that type exclusively.
This is not only more robust, it is also more flexible: you can change the container type later on and the code is likely to still work.
So, your code would become:
int main()
{
typedef std::map<int,float> m_type;
m_type m1;
m1.insert(m_type::value_type(10,15.0)); // allowed
m1.insert(m_type::value_type(12.0,13)); // no risk for a typo.
An alternative solution would be to wrap your float in a custom class. This isn't a bad thing to do anyway for (again) reasons of flexibility. It is rarely nice to have written code using a std::map<int, builtin-type> to then realize you need to store more data, and believe me that happens a lot. You might as well start with a class from the beginning.
There may well be a simpler way but this is what occurred to me:
#include <iostream>
#include <map>
template<typename Key, typename Value>
struct typesafe_pair
{
const Key& key;
const Value& value;
explicit typesafe_pair(const Key& key, const Value& value): key(key), value(value) {}
operator typename std::map<Key, Value>::value_type() { return typename std::map<Key, Value>::value_type(key, value); }
};
int main()
{
std::map<int,float>m1;
m1.insert(std::pair<int,float>(10,15.0)); // allowed
m1.insert(std::pair<float,int>(12.0,13)); // allowed!!
m1.insert(typesafe_pair<int,float>(10, 15.0)); // allowed
m1.insert(typesafe_pair<float, int>(12.0, 13)); // compiler error
std::cout << "map size=" << m1.size() << std::endl; //step -3
}
EDIT: 1 Someone may be able to provide a better (more efficient) solution involving rvalue references and perfect forwarding magic that I don't quite grasp yet.
EDIT 2: I think Carlo Wood has the best solution IMHO.

How to sort vector of pointer-to-struct

I'm trying to sort a concurrent_vector type, where hits_object is:
struct hits_object{
unsigned long int hash;
int position;
};
Here is the code I'm using:
concurrent_vector<hits_object*> hits;
for(i=0;...){
hits_object *obj=(hits_object*)malloc(sizeof(hits_object));
obj->position=i;
obj->hash=_prevHash[tid];
hits[i]=obj;
}
Now I have filled up a concurrent_vector<hits_object*> called hits.
But I want to sort this concurrent_vector on position property!!!
Here is an example of what's inside a typical hits object:
0 1106579628979812621
4237 1978650773053442200
512 3993899825106178560
4749 739461489314544830
1024 1629056397321528633
5261 593672691728388007
1536 5320457688954994196
5773 9017584181485751685
2048 4321435111178287982
6285 7119721556722067586
2560 7464213275487369093
6797 5363778283295017380
3072 255404511111217936
7309 5944699400741478979
3584 1069999863423687408
7821 3050974832468442286
4096 5230358938835592022
8333 5235649807131532071
I want to sort this based on the first column ("position" of type int). The second column is "hash" of type unsigned long int.
Now I've tried to do the following:
std::sort(hits.begin(),hits.end(),compareByPosition);
where compareByPosition is defined as:
int compareByPosition(const void *elem1,const void *elem2 )
{
return ((hits_object*)elem1)->position > ((hits_object*)elem2)->position? 1 : -1;
}
but I keep getting segmentation faults when I put in the line std::sort(hits.begin(),hits.end(),compareByPosition);
Please help!
Your compare function needs to return a boolean 0 or 1, not an integer 1 or -1, and it should have a strongly-typed signature:
bool compareByPosition(const hits_object *elem1, const hits_object *elem2 )
{
return elem1->position < elem2->position;
}
The error you were seeing are due to std::sort interpreting everything non-zero returned from the comp function as true, meaning that the left-hand side is less than the right-hand side.
NOTE : This answer has been heavily edited as the result of conversations with sbi and Mike Seymour.
int (*)(void*, void*) is the comparator for C qsort() function. In C++ std::sort() the prototype to the comparator is:
bool cmp(const hits_object* lhs, const hits_object* rhs)
{
return lhs->position < rhs->position;
}
std::sort(hits.begin(), hits.end(), &cmp);
On the other hand, you can use std::pair struct, which by default compares its first fields:
typedef std::pair<int position, unsigned long int hash> hits_object;
// ...
std::sort(hits.begin(), hits.end());
Without knowing what concurrent_vector is, I can't be sure what's causing the segmentation fault. Assuming it's similar to std::vector, you need to populate it with hits.push_back(obj) rather than hits[i] = j; you cannot use [] to access elements beyond the end of a vector, or to access an empty vector at all.
The comparison function should be equivalent to a < b, returning a boolean value; it's not a C-style comparison function returning negative, positive, or zero. Also, since sort is a template, there's no need for C-style void * arguments; everything is strongly typed:
bool compareByPosition(hits_object const * elem1, hits_object const * elem2) {
return elem1->position < elem2->position;
}
Also, you usually don't want to use new (and certainly never malloc) to create objects to store in a vector; the simplest and safest container would be vector<hits_object> (and a comparator that takes references, rather than pointers, as arguments). If you really must store pointers (because the objects are expensive to copy and not movable, or because you need polymorphism - neither of which apply to your example), either use smart pointers such as std::unique_ptr, or make sure you delete them once you're done with them.
The third argument you pass to std::sort() must have a signature similar to, and the semantics of, operator<():
bool is_smaller_position(const hits_object* lhs, const hits_object* rhs)
{
return lhs->position < rhs->position;
}
When you store pointers in a vector, you cannot overload operator<(), because smaller-than is fixed for all built-in types.
On a sidenote: Do not use malloc() in C++, use new instead. Also, I wonder why you are not using objects, rather than pointers. Finally, if concurrent_vector is anything like std::vector, you need to explicitly make it expand to accommodate new objects. This is what your code would then look like:
concurrent_vector<hits_object*> hits;
for(i=0;...){
hits_object obj;
obj.position=i;
obj.hash=_prevHash[tid];
hits.push_back(obj);
}
This doesn't look right:
for(i=0;...){
hits_object *obj=(hits_object*)malloc(sizeof(hits_object));
obj->position=i;
obj->hash=_prevHash[tid];
hits[i]=obj;
}
here you already are sorting the array based on 'i' because you set position to i as well as it becomes the index of hits!
also why using malloc, you should use new(/delete) instead. You could then create a simple constructor for the structure to initialize the hits_object
e.g.
struct hits_object
{
int position;
unsigned int hash;
hits_object( int p, unsigned int h ) : position(p), hash(h) {;}
};
then later write instead
hits_object* obj = new hits_object( i, _prevHash[tid] );
or even
hits.push_back( new hits_object( i, _prevHash[tid] ) );
Finally, your compare function should use the same data type as vector for its arguments
bool cmp( hits_object* p1, hits_object* p2 )
{
return p1->position < p2->position;
}
You can add a Lambda instead of a function to std::sort.
struct test
{
int x;
};
std::vector<test> tests;
std::sort(tests.begin(), tests.end(),
[](const test* a, const test* b)
{
return a->x < b->x;
});

C++ macro/metaprogram to determine number of members at compile time

I am working on an application with a message based / asynchronous agent-like architecture.
There will be a few dozen distinct message types, each represented by C++ types.
class message_a
{
long long identifier;
double some_value;
class something_else;
...//many more data members
}
Is it possible to write a macro/meta-program that would allow calculating the number of data members within the class at compile time?
//eg:
class message_b
{
long long identifier;
char foobar;
}
bitset<message_b::count_members> thebits;
I am not familiar with C++ meta programming, but could boost::mpl::vector allow me to accomplish this type of calculation?
as others already suggested, you need Boost.Fusion and its BOOST_FUSION_DEFINE_STRUCT. You'll need to define your struct once using unused but simple syntax. As result you receive required count_members (usually named as size) and much more flexibility than just that.
Your examples:
Definition:
BOOST_FUSION_DEFINE_STRUCT(
(), message_a,
(long long, identifier),
(double, some_value)
)
usage:
message_a a;
size_t count_members = message_a::size;
No, there is no way in C++ to know the names of all members or how many members are actually there.
You could store all types in a mpl::vector along in your classes but then you face the problem of how to turn them into members with appropriate names (which you cannot achieve without some macro hackery).
Using std::tuple instead of PODs is a solution that generally works but makes for incredible messy code when you actually work with the tuple (no named variables) unless you convert it at some point or have a wrapper that forwards accessors onto the tuple member.
class message {
public:
// ctors
const int& foo() const { return std::get<0>(data); }
// continue boiler plate with const overloads etc
static std::size_t nun_members() { return std::tuple_size<data>::value; }
private:
std::tuple<int, long long, foo> data;
};
A solution with Boost.PP and MPL:
#include <boost/mpl/vector.hpp>
#include <boost/mpl/at.hpp>
#include <boost/preprocessor.hpp>
#include <boost/preprocessor/arithmetic/inc.hpp>
struct Foo {
typedef boost::mpl::vector<int, double, long long> types;
// corresponding type names here
#define SEQ (foo)(bar)(baz)
#define MACRO(r, data, i, elem) boost::mpl::at< types, boost::mpl::int_<i> >::type elem;
BOOST_PP_SEQ_FOR_EACH_I(MACRO, 0, SEQ)
};
int main() {
Foo a;
a.foo;
}
I didn't test it so there could be bugs.
There are several answers simply saying that it is not possible, and if you hadn't linked to magic_get I would've agreed with them. But magic_get shows, to my amazement, that it actually is possible in some cases. This goes to show that proving that something is not possible is harder than proving that something is possible!
The short answer to your question would be to use the facilities in magic_get directly rather than reimplement them yourself. After all, even looking at the pre-Boost version of the code, it's not exactly clear how it works. At one point in the comments it mentions something about constructor arguments; I suspect this is the key, because it is possible to count the arguments to a regular function, so perhaps it is counting the number of arguments needed to brace-initialise the struct. This indicates that it may only be possible with plain old structs rather than objects with your own methods.
Despite all this, I would suggest using a reflection library as others have suggested. A good one that I often recommend is Google's protobuf library, which has reflection and serialisation along with multi-language support. However, it is intended only for data-only objects (like plain old structs but with vectors and strings).
Plain structs do not support counting members, but boost::fusion offers a good way to declare a struct that is count- and iteratable.
Something like this might get you closer:
struct Foo {
Foo() : a(boost::get<0>(values)), b(boost::get<1>(values)) {}
int &a;
float &b;
typedef boost::tuple<int,float> values_t;
values_t values;
};
If your types respect some properties ("SimpleAggregate"), you might use magic_get (which is now boost_pfr) (from C++14/C++17).
So you will have something like:
class message_b
{
public;
long long identifier;
char foobar;
};
static_assert(boost::pfr::tuple_size<message_b>::value == 2);

Literate Coding Vs. std::pair, solutions?

As most programmers I admire and try to follow the principles of Literate programming, but in C++ I routinely find myself using std::pair, for a gazillion common tasks. But std::pair is, IMHO, a vile enemy of literate programming...
My point is when I come back to code I've written a day or two ago, and I see manipulations of a std::pair (typically as an iterator) I wonder to myself "what did iter->first and iter->second mean???".
I'm guessing others have the same doubts when looking at their std::pair code, so I was wondering, has anyone come up with some good solutions to recover literacy when using std::pair?
std::pair is a good way to make a "local" and essentially anonymous type with essentially anonymous columns; if you're using a certain pair over so large a lexical space that you need to name the type and columns, I'd use a plain struct instead.
How about this:
struct MyPair : public std::pair < int, std::string >
{
const int& keyInt() { return first; }
void keyInt( const int& keyInt ) { first = keyInt; }
const std::string& valueString() { return second; }
void valueString( const std::string& valueString ) { second = valueString; }
};
It's a bit verbose, however using this in your code might make things a little easier to read, eg:
std::vector < MyPair > listPairs;
std::vector < MyPair >::iterator iterPair( listPairs.begin() );
if ( iterPair->keyInt() == 123 )
iterPair->valueString( "hello" );
Other than this, I can't see any silver bullet that's going to make things much clearer.
typedef std::pair<bool, int> IsPresent_Value;
typedef std::pair<double, int> Price_Quantity;
...you get the point.
You can create two pairs of getters (const and non) that will merely return a reference to first and second, but will be much more readable. For instance:
string& GetField(pair& p) { return p.first; }
int& GetValue(pair& p) { return p.second; }
Will let you get the field and value members from a given pair without having to remember which member holds what.
If you expect to use this a lot, you could also create a macro that will generate those getters for you, given the names and types: MAKE_PAIR_GETTERS(Field, string, Value, int) or so. Making the getters straightforward will probably allow the compiler to optimize them away, so they'll add no overhead at runtime; and using the macro will make it a snap to create those getters for whatever use you make of pairs.
You could use boost tuples, but they don't really alter the underlying issue: Do your really want to access each part of the pair/tuple with a small integral type, or do you want more 'literate' code. See this question I posted a while back.
However, boost::optional is a useful tool which I've found replaces quite a few of the cases where pairs/tuples are touted as ther answer.
Recently I've found myself using boost::tuple as a replacement for std::pair. You can define enumerators for each member and so it's obvious what each member is:
typedef boost::tuple<int, int> KeyValueTuple;
enum {
KEY
, VALUE
};
void foo (KeyValueTuple & p) {
p.get<KEY> () = 0;
p.get<VALUE> () = 0;
}
void bar (int key, int value)
{
foo (boost:tie (key, value));
}
BTW, comments welcome on if there is a hidden cost to using this approach.
EDIT: Remove names from global scope.
Just a quick comment regarding global namespace. In general I would use:
struct KeyValueTraits
{
typedef boost::tuple<int, int> Type;
enum {
KEY
, VALUE
};
};
void foo (KeyValueTuple::Type & p) {
p.get<KeyValueTuple::KEY> () = 0;
p.get<KeyValueTuple::VALUE> () = 0;
}
It does look to be the case that boost::fusion does tie the identity and value closer together.
As Alex mentioned, std::pair is very convenient but when it gets confusing create a structure and use it in the same way, have a look at std::pair code, it's not that complex.
I don't like std::pair as used in std::map either, map entries should have had members key and value.
I even used boost::MIC to avoid this. However, boost::MIC also comes with a cost.
Also, returning a std::pair results in less than readable code:
if (cntnr.insert(newEntry).second) { ... }
???
I also found that std::pair is commonly used by the lazy programmers who needed 2 values but didn't think why these values where needed together.