Cannot construct an std::map with a customer compare functor? - c++

#include <map>
using namespace std;
class C {
public:
C(map<int,int> m) { }
int operator()(int a, int b) {
return a < b;
}
};
int main() {
map<int, int> m;
map<int, int, C> mymap(C(m));
mymap.insert(pair<int,int>(1,1));
}
Why do I get the following error?:
main.cpp: In function 'int main()':
main.cpp:16:11: error: request for member 'insert' in 'mymap', which is of non-class type 'std::map<int, int, C>(C)'
mymap.insert(pair<int,int>(1,1));
Here is the coliru link: http://coliru.stacked-crooked.com/a/0413a35d3177ef48

This is an example of a vexing parse - function declaration, where you'd expect an object.
Try this:
map<int, int, C> mymap((C(m)));

map<int, int, C> mymap(C(m));
In this mymap is taken as a function. Change it to
map<int, int, C> mymap((C(m)));

In C++11 you can also avoid vexing parse by using brace initializer:
map<int, int, C> mymap(C{m});
(Though if would behave differently if C had a constructor C(std::initializer_list<T>) where map<int, int> would be implicitly convertible to T, so that constructor would be called instead)
Update: as Benjamin Bannier pointed out, you can use brace initializers everywhere:
map<int, int, C> mymap{C{m}};
or
map<int, int, C> mymap{C(m)};
With the same precaution: C shouldn't have operator std::pair<const int, int>().

Related

Getting compiler error: Request for member push in pq, which is of non-class type std::priority_queue

I am getting below error:
:60:8: error: request for member 'push' in 'pq', which is of
non-class type 'std::priority_queue,
std::vector >, std::function, std::pair)> >(comparator)' 60 | pq.push(p1);
My code is as below:
Declared a comparator for priority_queue as below:
class comparator
{
bool operator ()(std::pair<int, int> &p, std::pair<int, int> &q)
{
return (p.second < q.second);
}
};
Declared priority queue as below:
std::priority_queue<std::pair<int, int>, vector<std::pair<int, int>>, std::function<bool(pair<int, int>, pair<int, int>)>> pq(comparator);
make pair as below:
auto p1 = make_pair(1, 3);
pushed it to priority_queue as:
pq.push(p1);
Can anyone please tell, what i am doing wrong here
The operator() must be public and should also be const qualified.
You don't need std::function here. Just supply the comparator as the third template parameter directly.
#include <queue>
#include <utility>
#include <vector>
struct comparator {
// must be public and should be const qualified:
bool operator()(std::pair<int, int> &p, std::pair<int, int> &q) const {
return p.second < q.second;
}
};
int main() {
std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int>>,
comparator> // <- the proper comparator
pq;
auto p1 = std::make_pair(1, 3);
pq.push(p1);
}

Vector of pair with const member

As stated in this answer a std::vector<T> cannot contain const T, or classes with const-members. However, this is not the case when T = std::pair<const int, int>, as shown below. Why is this the case? How is std::pair special?
#include <utility>
#include <vector>
struct foo
{
const int first;
int second;
};
int main() {
std::vector<std::pair<const int, int>> V1;
V1.resize(3); // This compiles
std::vector<foo> V2;
V2.resize(3); // This gives the error listed below
}
error: use of deleted function 'foo::foo()'
note: 'foo::foo()' is implicitly deleted because the default definition would be ill-formed:
You are mixing two things here. The error that you get is due to the implicitly deleted foo() default constructor that std::vector::resize(size_type count) invokes:
If the current size is less than count,
1) additional default-inserted elements are appended
The std::pair template has a default constructor, this is why the call to V1.resize succeeds. If you provide one for foo as well, or allow its implicit generation by in class initialization, e.g.
struct foo
{
const int first = 42;
int second = 43;
};
then
std::vector<foo> V2;
V2.resize(3);
will happily compile. The operation that won't work out for both std::pair<const int, int> and foo is assignment. This won't compile:
V1[0] = std::pair<const int, int>(42, 43); // No way
V2[0] = { 42, 43 }; // Also not ok, can't assign to const data member
which doesn't have anything to do with std::vector, but with the const-qualified data members in both cases.

Why does this custom comparator fail in construcing std::priority_queue while it works for std::sort?

A comparator comp was defined as below. It works fine with std::sort, but fails to compile in the constructor of std::priority_queue. What is the problem? Thanks.
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
bool comp(int a, int b) { return a > b; }
int main()
{
vector<int> vec = {4, 2, 1, 3};
sort(vec.begin(), vec.end(), comp); // OK
priority_queue<int> q1(less<int>(), vec); // OK
priority_queue<int> q2(comp, vec); // Fail
return 0;
}
Error message:
error: no matching function for call to 'std::priority_queue<int>::priority_queue(bool (&)(int, int), std::vector<int>&)'
priority_queue<int> q2(comp, vec);
^
The type of the default comparator of std::priority_queue is std::less<T> where T is the value type. You are passing something of type bool(*)(int, int) instead. std::sort() being a function can deduce the comparator's type. Class types can't deduce their template arguments (yet - there us discussion in the C++ committee that a future version may have class templates whose template arguments can be deduced.
You can use
std::priority_queue<int, std::vector<int>, bool(*)(int, int)> q(comp);
or, avoiding a hard-to-inline function pointer:
std::priority_queue<int, std::vector<int>, std::greater<int> > q;

error for hash function of pair of ints

I have the following class with an unordered_map member, and a hash function defined for pair<int,int>
class abc
{public :
unordered_map < pair<int,int> , int > rules ;
unsigned nodes;
unsigned packet ;
};
namespace std {
template <>
class hash < std::pair< int,int> >{
public :
size_t operator()(const pair< int, int> &x ) const
{
size_t h = std::hash<int>()(x.first) ^ std::hash<int>()(x.second);
return h ;
}
};
}
But I am getting the following errors :
error: invalid use of incomplete type ‘struct std::hash<std::pair<int, int> >
error: declaration of ‘struct std::hash<std::pair<int, int> >
error: type ‘std::__detail::_Hashtable_ebo_helper<1, std::hash<std::pair<int, int> >, true>’ is not a direct base of ‘std::__detail::_Hash_code_base<std::pair<int, int>, std::pair<const std::pair<int, int>, int>, std::__detail::_Select1st, std::hash<std::pair<int, int> >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, true>’
Unfortunately, this program has undefined behavior. C++11 §17.6.4.2.1:
A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.
hash<pair<int,int>> depends on primitive and standard library types only. This is easily worked around by defining your hash class outside of namespace std, and using that hash explicitly in your map declaration:
struct pairhash {
public:
template <typename T, typename U>
std::size_t operator()(const std::pair<T, U> &x) const
{
return std::hash<T>()(x.first) ^ std::hash<U>()(x.second);
}
};
class abc {
std::unordered_map<std::pair<int,int>, int, pairhash> rules;
};
EDIT: I've used xor to combine the hashes of the pair members here because I'm lazy, but for serious use xor is a fairly crappy hash combining function.
I prefer to rely on the standard implementation of std::hash<uintmax_t> to mix hashes of components of an std::pair:
#include <functional>
#include <utility>
struct hash_pair final {
template<class TFirst, class TSecond>
size_t operator()(const std::pair<TFirst, TSecond>& p) const noexcept {
uintmax_t hash = std::hash<TFirst>{}(p.first);
hash <<= sizeof(uintmax_t) * 4;
hash ^= std::hash<TSecond>{}(p.second);
return std::hash<uintmax_t>{}(hash);
}
};

Compilation error with Type Traits in boost::type_traits::conditional

I am having a problem in some code using type_traits from boost.
It is quite a complex part of the code, but I could isolate the part that gives the compilation error:
template<const size_t maxLen>
class MyString {
public:
typedef boost::conditional<(maxLen > 0), char[maxLen+1], std::string> ObjExternal;
};
template <class T>
class APIBase {
public:
typedef T obj_type;
typedef typename T::ObjExternal return_type;
};
template <class T>
int edit(const T& field, const typename T::return_type& value)
{
return 0;
}
int myFunction()
{
APIBase<MyString<10> > b;
char c[11];
return edit(b, c);
}
This gives the following error:
test.cpp: In function ‘int myFunction()’:
tes.cpp:109: error: no matching function for call to ‘edit(APIBase >&, char [11])’
tes.cpp:100: note: candidates are: int edit(const T&, const typename T::return_type&) [with T = APIBase >]
However, if I change the line with the code
char c[11];
by
MyString<10>::ObjExternal c;
it works. Similarly, if instead I change the line
typedef boost::conditional<(maxLen > 0), char[maxLen+1], std::string> ObjExternal;
by
typedef char ObjExternal[maxLen+1];
it also works. I am thinking that it is a problem with boost::conditional, as it seems it is not being evaluated right. Is there a problem in my code, or there is an alternative that can be used instead of boost::conditional to have this functionality?
I am thinking about using the 2nd option, but then I could not use maxLen as 0.
You need to use the member typedef type provided by conditional and not the conditional type itself.
Change:
typedef boost::conditional<(maxLen > 0),
char[maxLen+1],
std::string> ObjExternal;
to:
typedef typename boost::conditional<(maxLen > 0),
char[maxLen+1],
std::string>::type ObjExternal;