boost bimap set_of with user defined comparator - c++

I plan to use my own compare function with boost bimap. The issue i am trying to address is when i use boost bimap with a pointer, the comparison should not compare the two pointers but should compare the class which is pointed by the pointer.
I tried the following code. But it doesn't even compile. What am i doing wrong? Also is there a simpler way to achieve less function that compares two objects and not two pointers pointers)
typedef std::set<int> ruleset;
template <class myclass>
bool comp_pointer(const myclass &lhs, const myclass &rhs)
{
return ((*lhs) < (*rhs));
}
typedef boost::bimap<set_of<ruleset *, comp_pointer<ruleset *> >, int> megarulebimap;
Error messages:
party1.cpp:104:64: error: type/value mismatch at argument 2 in template parameter list for 'template struct boost::bimaps::set_of'
party1.cpp:104:64: error: expected a type, got 'comp_pointer'
party1.cpp:104:70: error: template argument 1 is invalid
party1.cpp:104:85: error: invalid type in declaration before ';' token

typedef std::set<int> ruleset;
struct ruleset_cmp {
bool operator()(const ruleset *lhs, const ruleset *rhs) const
{
return ((*lhs) < (*rhs));
}
};
typedef boost::bimap<set_of<ruleset *, ruleset_cmp>, int> megarulebimap;
Okay. The above snippet works. It appears a functor needs to be used here.

Related

What is the correct template parameter/argument for operator[] as a member function?

In an attempt to call a function template which accepts a type and a parameter/argument of that type as the template parameters/arguments, compiler gives an error which is not produced with similar parameters/arguments. So I was wondering what is the correct parameters/arguments in case of calling the function templates for the member function "operator[]const" of a vector class!
Consider this piece of code:
class test_class{
public:
int member;
int& operator[](size_t) {return member;}
const int& operator[](size_t) const{return member;}
};
typedef std::vector<int> vector_type;
typedef const int&(test_class::* OK_type)(size_t)const;
typedef const int&(vector_type::* not_OK_type)(size_t)const;
static constexpr OK_type OK_pointer = &test_class::operator[];
static constexpr not_OK_type not_OK_pointer = &vector_type::operator[];
template<typename t__, t__>
void function(){}
The above code is alright now consider the main function:
int main() {
function<OK_type, OK_pointer>();
function<not_OK_type, not_OK_pointer>();
return 0;
}
The first call of the function template is OK but not the second one.
The error which compiler produce is:
error: no matching function for call to ‘function<not_OK_type, not_OK_pointer>()’
note: candidate: ‘template<class t__, t__ <anonymous> > void function()’
note: template argument deduction/substitution failed:
error: ‘const int& (std::vector<int>::*)(size_t) const{((const int& (std::vector<int>::*)(size_t) const)std::vector<int>::operator[]), 0}’ is not a valid template argument for type ‘const int& (std::vector<int>::*)(long unsigned int) const’
function<not_OK_type, not_OK_pointer>();
note: it must be a pointer-to-member of the form ‘&X::Y’
Interestingly even if the function template was formed as:
template<auto>
void function(){}
it would cause the same result.
I must add that in the case of non const version, error is the same (for std::vector).
So I am wondering
A: what is wrong?
B: Considering that if there was a mismatch between the not_OK_type and &vector_type::operator[], then compiler would also give an error in case of:
static constexpr not_OK_type not_OK_pointer = &vector_type::operator[];
Is there a difference between types that can be used as constexpr and the type that can be used as a template parameter/argument?
The issue is typedef const int&(vector_type::* not_OK_type)(size_t)const;.
If you see stl_vector.h (here), the operator[] is declared as noexcept at line 1040.
But in the declaration of not_OK_type variable, noexcept is not present. That's why the compiler complains.
For getting rid of compilation error, add noexcept to not_OK_type variable. Like this:
typedef const int&(vector_type::* not_OK_type)(size_t)const noexcept;
Working code:
#include <vector>
class test_class{
public:
int member;
int& operator[](size_t) {return member;}
const int& operator[](size_t) const{return member;}
};
typedef std::vector<int> vector_type;
typedef const int&(test_class::* OK_type)(size_t)const;
typedef const int&(vector_type::* not_OK_type)(size_t)const noexcept;
static constexpr OK_type OK_pointer = &test_class::operator[];
static constexpr not_OK_type not_OK_pointer = &vector_type::operator[];
template<typename t__, t__>
void function(){}
int main() {
function<OK_type, OK_pointer>();
function<not_OK_type, not_OK_pointer>();
return 0;
}
#Kunal Puri, provided a correct answer for the the section A of the question.
As for the section B of the question, I guess the clue can be found in one exception that applies when converted constant expression used as template argument for a non-type template parameter.
According to (https://en.cppreference.com/w/cpp/language/constant_expression), a converted constant expression under certain condition and specifically in case of conversion of pointer to noexcept function to pointer to function is a constant expression. Which explains why compiler did not produce an error in case of:
static constexpr not_OK_type not_OK_pointer = &vector_type::operator[];
However according to (https://en.cppreference.com/w/cpp/language/template_parameters), this type of converted constant expression can not be used as a pointer to non-static data members(and maybe also a pointer to non-static member functions) for a non-type template parameter.
This exception might be the source of conflict between types that can be used as constexpr and as template argument, although statements in the later source are vague and not directly linked to the case.

How to use weak_ptr in tbb::concurrent_unordered_map?

I am using tbb::concurrent_unordered_map to replace std::map in my program like this:
Before:
class KvSubTable;
typedef std::weak_ptr<KvSubTable> KvSubTableId;
std::map<KvSubTableId, int, std::owner_less<KvSubTableId> > mEntryMap;
Now, I use tbb::concurrent_unordered_map to replace std::map , but it has some compile errors:
tbb::concurrent_unordered_map<KvSubTableId, int, tbb::tbb_hash<KvSubTableId>, std::owner_less<KvSubTableId> > mEntryMap;
cpp/ext/amd64/include/tbb/internal/_tbb_hash_compare_impl.h:66:37:
error: invalid static_cast from type 'const
std::weak_ptr' to type 'std::size_t
{aka long unsigned int}'
return static_cast( t ) * internal::hash_multiplier;
I have try some solutions like this , but it does not work:
template <typename T>
inline bool operator==(const std::weak_ptr<T>& t, const std::weak_ptr<T>& u)
{
return !t.owner_before(u) && !u.owner_before(t);
}
So, how can it work, please help....
You need to define a hash function for std::weak_ptr. You can find the example in tests for the TBB library.

Syntax to pass argument to unordered_set hash function in c++

I have created a hasher class for a custom type I'm using, but it has a constructor that takes an argument. I can't figure out the syntax to use this in an unordered_set.
class Hasher {
unsigned arg;
public:
Hasher(unsigned a) : arg(a) {}
size_t operator()(const MyType& t) const {
return calculate_hash(arg, t);
}
}
int main() {
unordered_set<MyType, Hasher(2)> myset; // compilation error
}
The error message:
In file included from Tetrahedron.cc:5:
./Triangulation.h:52:29: error: template argument for template type parameter must be a type
unordered_set<TetraFace,FaceHasher(2)> faces2;
^~~~~~~~~~~~~
/bin/../lib/gcc/x86_64-redhat-linux/6.3.1/../../../../include/c++/6.3.1/bits/unordered_set.h:90:11: note: template parameter is declared here
class _Hash = hash<_Value>,
^
I also tried
unordered_set<MyType, Hasher> myset(Hasher(2));
but I still get an error:
In file included from Tetrahedron.cc:5:
./Triangulation.h:52:59: error: expected ')'
unordered_set<TetraFace,FaceHasher> faces2(FaceHasher(2));
^
./Triangulation.h:52:58: note: to match this '('
unordered_set<TetraFace,FaceHasher> faces2(FaceHasher(2));
^
You're getting a compile error there because you're trying to pass an object (i.e. instance) of type Hasher as a template argument.
Like your error describes: template argument for template type parameter must be a type
It's expecting a type, and you're passing in a value.
Parameterize the arg at the type level.
template<unsigned A>
class Hasher {
unsigned arg = A;
public:
size_t operator()(const int& t) const {
std::cout << arg << std::endl;
return 0;
}
};
int main() {
std::unordered_set<int, Hasher<2>> myset;
myset.insert(5); // prints 2
std::unordered_set<int, Hasher<3>> myset2;
myset2.insert(3); // prints 3
}
Unfortunately it is not possible to construct a std::unorderd_set with just the hash object. All of the constructors that take the hash object have a parameter before it for bucket_count. You would need to specify the value for it like
unordered_set<MyType, Hasher> myset(some_bucket_count_value, Hasher(2));
If you do not want to do that then you have to make Hasher default constructable.
Also not that
return calculate_hash(arg);
Is not going to work as you will always hash arg no matter what MyType you pass. You need to be hashing the MyType object for the std::unordered_set to really work.

recursive variant container compiler error

I'd like a variant contain copies of objects of its type. Somehow it is not working:
struct value
{
};
class json;
using json = ::boost::variant<
::std::vector<::std::unique_ptr<json> >,
::std::unordered_map<::std::string, ::std::unique_ptr<json> >,
value
>;
json.hpp:116:2: error: conflicting declaration 'using json = '
>;
^
json.hpp:110:7: error: 'class json' has a previous declaration as 'class json'
class json;
I know of 2 workarounds already: ::std::unique_ptr<void>, with a custom deleter, as well as the possibility of using ::boost::any instead of the variant, but are these the only ways? The problem with ::boost::any is that I need to enable RTTI for it to work.
What about:
struct json : ::boost::variant<
::std::vector<::std::unique_ptr<json> >,
::std::unordered_map<::std::string, ::std::unique_ptr<json> >,
value
>
{
using variant::variant;
template <typename U>
json& operator=(U&& u)
{
variant::operator=(::std::forward<U>(u));
return *this;
}
};
That would be the solution, except it doesn't work for me with g++ (constructing json out of vector fails because of ambiguous constructor call). Construction from a const reference to such a vector works, but not not from a non-const reference. I have no idea why. In addition, unique_ptr doesn't work with boost::variant for me because it's uncopyable (shared_ptr does work).

Boost lambda with std::find_if does not compile

Consider this template member method of some class:
template<typename T>
bool elementIsInSharedPtrVector(const T& p_elem, const std::vector< boost::shared_ptr< T > >& p_Vector) const
{
return (std::find_if(p_Vector.begin(), p_Vector.end(), **boost::lambda::_1 == p_elem) != p_Vector.end());
}
The compiler gives this error(besides hundreds of template errors):
usr/include/boost/pointee.hpp:30: error: no type named 'element_type' in 'struct SLnAdjW'
The type SLnAdjW is a POD C struct with a free defined == operator function.
What I'm doing wrong here?