Say I have a class that can easily express key-value semantics:
template <class T1, class T2>
struct data_t{
T1 m1;
T2 m2;
};
What would be the most efficient way to create an unordered map out of a vector of such structs?
My approach
I tried to define a conversion operator for my class
operator std::pair<T1, T2> () { return {m1, m2}; } // typo noted by PasserBy
But this doesn't seem to work
std::vector<data_t> v;
std::unordered_map<T1, T2> um(v.begin(), v.end()); // compilation error
My particular use case has a pointer type T1 and a value type T2 so I suppose there wouldn't be a need to define hash functions (?). Also the reason I'm trying to do it through a conversion operator is to be able to add elements to that unordered map in the same fashion:
um.insert(itn, ite); // insert from a range of the source vector
I would just use transform:
unordered_map<int, double> um;
transform(begin(v), end(v), inserter(um, end(um)), [](const auto& data) {
return make_pair(data.m1, data.m2);
});
First, there is a typo in your conversion operator
operator std::pair<T1, T2>() const { return {m1, m2}; }
And it should generally be marked const too.
The reason for a compile error is that unordered_map<T1, T2> holds std::pair<const T1, T2>, which your vector doesn't hold.
So this works
std::vector<data_t<const T1, T2>> v;
std::unordered_map<T1, T2> um(v.begin(), v.end());
provided that T1 has a proper hash function.
So does using a different conversion operator
operator std::pair<const T1, T2>() const { return {m1, m2}; }
std::vector<data_t<T1, T2>> v;
std::unordered_map<T1, T2> um(v.begin(), v.end());
Related
I have 2 overloaded function say - func1 and func2 -
Func1 is -
template<typename T1, typename T2> bool AreIdentical(const std::pair<T1, T2>
&lhs, const std::pair<T1, T2> &rhs)
{
//some code
}
Func2 is -
template<typename T> bool AreIdentical(typename std::map<int,
std::vector<T>>::iterator itOrig,
typename std::map<int, std::vector<T>>::iterator itNew)
{
//some code
}
I am trying to call the function AreIdentical in below manner -
int main()
{
std::map<int, std::vector<int>> orgitem;
std::map<int, std::vector<int>> newitem;
newitem[0];
orgitem[0];
AreIdentical(*orgitem.begin(), *newitem.begin());
return 0;
}
Now, interesting thing is, my origitem and newitem is of map type but always Func1 is getting called which takes parameter pair type instead of Func2.
Do anyone have any clue why is it happening so?
orgitem.begin() is an iterator. But *orgitem.begin() is the object the iterator points at, which is a std::pair<const int, std::vector<int>>.
If you had
AreIdentical(orgitem.begin(), newitem.begin());
without the dereferencing * operators, that would not be able to call the pair overload.
But in fact it won't work either, because in your second overload the parameter T is not in a deducible context. The only way to call it is:
AreIdentical<int>(orgitem.begin(), newitem.begin());
You might be able to "fix" this by changing the iterator overload to just accept any iterator whose value type has members first and second:
template <typename Iter>
auto AreIdentical(Iter itOrig, Iter itNew)
-> decltype((*itOrig).first, (*itOrig).second, bool{});
Is it possible to return an empty pair from a function? Meaning, follow the rules of the function prototype, but do not have any elements in the pair (e.g. NULL). Understanding that a pair simply exists so I don't know if this is conceptually possible. I have a need to return a pair that is NULL or empty, if that makes any sense.
For example,
pair<int, int> MyClass::someFunction()
{
// do something that means we need to return an empty pair
return NULL; // <--- this does not work obviously
}
Unfortunately, boost is not a possibility for me.
Generally speaking an empty pair doesn't even make sense. Afterall a pair is per definition a container containing two objects.
You could however make something like an empty pair using Boost.Optional. Then you would either use a boost::optional<std::pair<...>> giving you the option of returning either a pair or an empty state or use std::pair<boost::optional<...>, boost::optional<...>> for a pair where either object could be empty.
You can returns pointer... Or use boost::optional<T>. Optional will be better...
boost::optional<std::pair<int, int> > MyClass::someFunction()
{
return boost::optional<std::pair<int, int> >();
}
void f(const MyClass& f)
{
boost::optional<std::pair<int, int> > ret = f.someFunction();
if (!ret) // empty
{
...
}
}
The answer to your questions is easily explained by considering the way the C++ compiler generates code in this case.
The std::pair<int, int> is returned-by-value.
Since MyClass::someFunction() is returning an object by value, the sequence of events is as follows:
The calling function reserves space on the stack for a std::pair<int, int>
The MyClass::someFunction() is called
The right hand side of the return statement is a assignment to the location reserved on the stack earlier. There is an implicit construction of a std::pair<int, int> taking place.
Thus returning a NULL pointer is impossible.
It wouldn't take much to create your own "optional pair" (similar to boost::optional<std::pair<…>>, but with a different interface), e.g.:
template <typename T1, typename T2> struct OptPair : std::pair<T1, T2>
{
typedef std::pair<T1, T2> base_t;
bool contains;
OptPair() : contains(true) {}
explicit OptPair(bool x) : contains(x) {}
OptPair(const T1& x, const T2& y) : base_t(x, y), contains(true) {}
template <class U, class V>
OptPair(const std::pair<U,V> &p) : base_t(p), contains(true) {}
template <class U, class V> OptPair(const OptPair<U,V> &p) : base_t(p), contains(p.contains) {}
// No need to define operator=, as the default will construct an OptPair<T1, T2>
// if necessary, then copy members into *this.
};
template <typename T1, typename T2>
OptPair<T1, T2> makeOptPair() { return OptPair<T1, T2>(); }
template <typename T1, typename T2>
OptPair<T1, T2> makeOptPair(const T1 &x, const T2 &y) {
OptPair<T1, T2> p(true);
p.first = x;
p.second = y;
return p;
}
template <typename OS, typename T1, typename T2>
OS &operator<<(OS &os, const OptPair<T1, T2>& p) {
os << "<OptPair: ";
if (p.contains) os << p.first << ", " << p.second;
else os << "empty";
os << ">";
return os;
}
Then you can use it just like std::pair (and even use it interchangeably with std::pair, assigning values back and forth), but with the added ability to pass an "empty" value back like this:
OptPair<int, int> someFunction()
{
...
return OptPair<int, int>(false);
}
You have to make sure to check the result before using it, like this:
void doStuffWithPair(std::pair<int, int>);
void doStuffWithEmpty();
...
OptPair<int, int> ret = someFunction();
if (ret.contains) doStuffWithPair(ret);
else doStuffWithEmpty();
A pair, by definition, has 2 elements. It cannot have none.
You need something like boost::optional<std::pair<T1,T2>>. Then you can choose to have a pair or not. You can find documentation for boost::optional here.
Is it valid to have a std::pair of references ? In particular, are there issues with the assignment operator ? According to this link, there seems to be no special treatment with operator=, so default assignement operator will not be able to be generated.
I'd like to have a pair<T&, U&> and be able to assign to it another pair (of values or references) and have the pointed-to objects modified.
In C++11 you can use std::pair<std::reference_wrapper<T>, std::reference_wrapper<U>> and the objects of that type will behave exactly as you want.
No, you cannot do this reliably in C++03, because the constructor of pair takes references to T, and creating a reference to a reference is not legal in C++03.
Notice that I said "reliably". Some common compilers still in use (for GCC, I tested GCC4.1, #Charles reported GCC4.4.4) do not allow forming a reference to a reference, but more recently do allow it as they implement reference collapsing (T& is T if T is a reference type). If your code uses such things, you cannot rely on it to work on other compilers until you try it and see.
It sounds like you want to use boost::tuple<>
int a, b;
// on the fly
boost::tie(a, b) = std::make_pair(1, 2);
// as variable
boost::tuple<int&, int&> t = boost::tie(a, b);
t.get<0>() = 1;
t.get<1>() = 2;
I think it would be legal to have a std::pair housing references. std::map uses std::pair with a const type, after all, which can't be assigned to either.
I'd like to have a pair<T&, U&> and be able to assign to it another pair
Assignment won't work, since you cannot reset references. You can, however, copy-initialize such objects.
You are right. You can create a pair of references, but you can't use operator = anymore.
I was thinking along the same lines as you, I think. I wrote the following class to scratch this particular itch:
template <class T1, class T2> struct refpair{
T1& first;
T2& second;
refpair(T1& x, T2& y) : first(x), second(y) {}
template <class U, class V>
refpair<T1,T2>& operator=(const std::pair<U,V> &p){
first=p.first;
second=p.second;
return *this;
}
};
It allows you to do horrible things like:
int main (){
int k,v;
refpair<int,int> p(k,v);
std::map<int,int>m;
m[20]=100;
m[40]=1000;
m[60]=3;
BOOST_FOREACH(p,m){
std::cout << "k, v = " << k << ", " << v << std::endl;
}
return 0;
}
(remember the relevant includes).
The nastiness is of course that the references to k and v that I am assigning to are hidden inside p.
It almost becomes pretty again if you do something like this:
template <class T1,class T2>
refpair<T1,T2> make_refpair (T1& x, T2& y){
return ( refpair<T1,T2>(x,y) );
}
Which allows you to loop like this:
BOOST_FOREACH(make_refpair(k,v),m){
std::cout << "k, v = " << k << ", " << v << std::endl;
}
(All comments are welcome as I am in no way a c++ expert.)
I don't know what is "wrong" with std::pair in C++03 but if I reimplement it naively, I don't have any problem with it, (using the same compiler gcc and clang).
double a = 1.;
double b = 2.;
my::pair<double, double> p1(5., 6.);
my::pair<double&, double&> p2(a, b);
p2 = p1; // a == 5.
So a workaround could be to (1) reimplement pair (in a different namespace), or (2) specialize for std::pair<T&, T&>, or (3) simply use C++11 (where std::pair for refs works out of the box)
(1) Here it is the naive implementation
namespace my{
template<class T1, class T2>
struct pair{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair(T1 const& t1, T2 const& t2) : first(t1), second(t2){}
template<class U1, class U2> pair(pair<U1, U2> const& p) : first(p.first), second(p.second){}
template<class U1, class U2>
pair& operator=(const pair<U1, U2>& p){
first = p.first;
second = p.second;
return *this;
}
};
template<class T1, class T2>
pair<T1, T2> make_pair(T1 t1, T2 t2){
return pair<T1, T2>(t1, t2);
}
}
(2) And here it is an specialization of std::pair (some people may complain that I am messing around overloading/specializing with the std namespace, but I think it is ok if it is to extend the capabilities of the class)
namespace std{
template<class T1, class T2>
struct pair<T1&, T2&>{
typedef T1& first_type; /// #c first_type is the first bound type
typedef T2& second_type; /// #c second_type is the second bound type
first_type first;
second_type second;
pair(T1& t1, T2& t2) : first(t1), second(t2){}
template<class U1, class U2> pair(pair<U1, U2> const& p) : first(p.first), second(p.second){}
template<class U1, class U2>
pair& operator=(const pair<U1, U2>& p){
first = p.first;
second = p.second;
return *this;
}
};
}
Maybe I am missing something obvious, I can edit the answer if some obvious flaws, are pointed.
Post c++14, you can do:
int a, b;
auto const p(std::make_pair(std::ref(a), std::ref(b)));
Using std::cref() is also possible.
I ended up solving a similar problem by just building a really simple structure. I didn't even worry about the assignment operator since the default one should work fine.
template<class U, class V>
struct pair
{
pair(U & first, V & second): first(first), second(second) {}
U & first;
V & second;
}
In definition of pair class in c++ there are two typedefs. what are they for? there are no use of them in the code!
template <class T1, class T2> struct pair
{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair() : first(T1()), second(T2()) {}
pair(const T1& x, const T2& y) : first(x), second(y) {}
template <class U, class V>
pair (const pair<U,V> &p) : first(p.first), second(p.second) { }
}
They are just here for you convenience, so you can use them in your code. C++ doesn't have a reflection model , so that's the only way you have "know" what types they are
Suppose you define your own pair
typedef pair MyPair;
Then you can use
MyPair::first_type
MyPair::second_type
for example,
MyPair::first_type my_first(MyPair& pair)
{
return pair.first;
}
Then you won't need to research and replace everywhere in your code , if you change the original definition of MyPair.
It's to allow other pieces of code to declare variables of the types without having direct access to the type parameters (T1 & T2). A similar, less trivial, example are the typedefs in container classes:
vector<int>::iterator curNum;
for(curNum = someVect.begin(); curNum != someVect.end(); curNum++)
; //do stuff
This uses the typedef iterator defined in the vector template to create curNum. It will be somewhat less useful come C++0x's auto keyword:
for(auto curNum = someVect.begin(); curNum != someVect.end(); curNum++)
;
This is so you can refer to the types in your code using e.g. pair<int,string>::first_type myVariable, or if you've typedef'd a particular flavour of the template then MyPair::first_type myVariable.
They are public aliases of the passed-in T1 and T2 types that can be referenced after the object is constructed.
is it safe to memcopy myvect.size()*sizeof(foo) bytes from the memoryadress of the first element of a
std::vector<std::pair<T1, T2> > myvect
into an array of
struct foo{
T1 first;
T2 second;
}
if the array is allocated with the same number of elements as the vector's size?
thanks
No, a class containing T1 and T2 is not guaranteed the same layout or alignment as std::pair<T1, T2>, at least in C++98 (since std::pair is not a POD type). The story may be different in C++0x.
The answer to the question you didn't ask is probably std::transform:
struct pairToFoo {
// optionally this can be a function template.
// template<typename T1, typename T2>
foo operator()(const std::pair<T1,T2> &p) const {
foo f = {p.first, p.second};
return f;
}
};
std::transform(myvect.begin(), myvect.end(), myarray, pairToFoo());
Or std::copy, but give foo an operator= taking a pair as parameter. This assumes you can re-write foo, though:
struct foo {
T1 first;
T2 second;
foo &operator=(const std::pair<T1,T2> &p) {
first = p.first;
second = p.second;
return *this;
}
};
std::copy(myvect.begin(), myvect.end(), myarray);
In general, no. On some platforms/compilers/STL implementations it might be, but don't do it anyway. You'd be relying on the implementation details of both pair<> and vector<>.
I myself have committed the sin of relying on vector<> being a contiguous array. For that, I deeply repent. But the pair<>... Just say no.