I was trying boost-variant with custom classes. I understood that a safe way to access the content of a class is using boost::static_visitor. Do you know why the code below doesn't compile? Are there any requirement on the signature/declaration of boost::static_visitor in order to be used?
I found this question Why can't I visit this custom type with boost::variant? but I didn't get it.
Regards
AFG
#include <iostream>
#include <algorithm>
#include <boost/variant.hpp>
struct CA{};
struct ca_visitor : public boost::static_visitor<CA>
{
const CA& operator()(const CA& obj ) const { return obj;}
};
struct CB{};
struct cb_visitor : public boost::static_visitor<CB>
{
const CB& operator()(const CB& obj) const { return obj;}
};
int main(){
typedef boost::variant<
CA
,CB > v_type;
v_type v;
const CA& a = boost::apply_visitor( ca_visitor(), v );
}
First of all, the template argument of boost::static_visitor<> should specify the type returned by the call operator. In your case, ca_visitor's call operator returns a CA const&, not a CA.
But that is not the biggest issue. The biggest issue is that you seem to have a misconception of how variant<> and static_visitor<> should work.
The idea of a boost::variant<> is that it can hold values of any of the types you specify in the template argument list. You don't know what that type is, and therefore you provide a visitor with several overloaded call operators for handling each possible case.
Therefore, when you provide a visitor, you need to make sure it has all necessary overloads of operator() that accept the types your variant can hold. If you fail to do so, Boost.Variant causes a compilation error to be generated (and is doing you a favor, because you forgot to handle some cases).
This is the issue you are facing: your visitor does not have a call operator accepting an object of type CB.
This is an example of a correct use of boost::variant<> and static_visitor<>:
#include <iostream>
#include <algorithm>
#include <boost/variant.hpp>
struct A{};
struct B{};
struct my_visitor : public boost::static_visitor<bool>
// ^^^^
// This must be the same as the
// return type of your call
// operators
{
bool operator() (const A& obj ) const { return true; }
bool operator() (const B& obj) const { return false; }
};
int main()
{
A a;
B b;
my_visitor mv;
typedef boost::variant<A, B> v_type;
v_type v = a;
bool res = v.apply_visitor(mv);
std::cout << res; // Should print 1
v = b;
res = v.apply_visitor(mv);
std::cout << res; // Should print 0
}
Related
The problem in question is related to the question and discussion found in this SO thread.
The problem is essentially as follows, I have an abstract class called players. Then I have two classes attackers and defenders. Now, I would like to have an unordered container (map, set, etc.) containing all players. For that I need a hash function (which is not the issue as both attackers and defenders have names) and an equality function. The latter is the problem. As discussed in the linked SO thread, it seems to be bad practice to inherit operator== and I can see why.
I now wonder what the idiomatic solution to my problem is. Is it to just have two containers? One for players and one for attackers? Are there other solutions?
Edit:
Yes, I am talking about unordered_* containers. I am aware that I would need to store pointers in the containers rather than objects themselves. For example, I'd have a container std::unordered_set<std::shared_ptr<players>> all_players.
When you instantiate your map, you can specify a comparator:
template< class InputIt >
map( InputIt first, InputIt last,
const Compare& comp = Compare(), /// << this here
const Allocator& alloc = Allocator() );
Reference: https://en.cppreference.com/w/cpp/container/map/map
Then, you don't need to define the equality operator. In any case, in order to store polymorphic objects in a map, you'll need to store pointers.
So, you would need a comparator anyway, in order to compare the objects, not the pointer values.
In order to store multiple different types in the same container, you have to take advantage of polymorphism.
Polymorphism requires you to use pointers to objects instead of actual objects. That's because C/C++ doesn't allow you to make arrays of multiple different types. The best way to do that in modern C++ is to use std::unique_ptr or std::shared_ptr from #include <memory>
To make a polymorphic container you'll need the following:
A common base struct/class that all of your types inherit from.
Some way to interface with subtype-specific methods/members.
This can be a virtual method in the base object, a member of the base object, or you can also use typeid to figure out what type something is at runtime.
#include <iostream>
#include <vector>
#include <memory>
#include <typeinfo>
struct base {
virtual ~base() = default;
virtual int GetValue() const = 0;
};
struct A : base {
int a;
A(const int v) : a{ v } {}
int GetValue() const override { return a; }
void doSomething() const { std::cout << "Hello World!"; }
};
struct B : base {
int b;
int mult;
B(const int v, const int mult) : b{ v }, mult{ mult } {}
int GetValue() const override { return b * mult; }
void doSomethingElse() const { std::cout << "!dlroW olleH"; }
};
int main()
{
std::vector<std::unique_ptr<base>> vec;
vec.emplace_back(std::make_unique<A>(5)); //< insert an object of type A
vec.emplace_back(std::make_unique<B>(8, 2)); //< insert an object of type B
for (const auto& it : vec) {
std::cout << it->GetValue() << '\t';
if (typeid(*it.get()) == typeid(A)) {
((A*)it.get())->doSomething();
}
else if (typeid(*it.get()) == typeid(B)) {
((B*)it.get())->doSomethingElse();
}
std::cout << std::endl;
}
}
Outputs:
5 Hello World!
16 !dlroW olleH
You need a hash function-object that looks through your pointers. The base class can have non-virtual implementations, or equivalently you can have the hasher inspect the public members.
class players {
public:
size_t hash() const;
friend bool operator==(const player & lhs, const player & rhs);
};
using std::unique_ptr<players> players_ptr;
struct players_hash {
size_t operator()(const players_ptr & ptr) { return ptr->hash(); }
};
struct players_equal {
bool operator()(const players_ptr & lhs, const players_ptr & rhs) { return *lhs == *rhs; }
};
std::unordered_set<players_ptr, players_hash, players_equal> all_players;
I have a cusom implemented Heap for priority queue application
class Heap {
SomeCutsomClass elements[100];
....
....
};
Now I need to support two different comparison operation between the keys of the heap and I want to implement it using c++ predicates
struct less1
{
bool operator()(const SomeCutsomClass& c1, const SomeCutsomClass& c1)
{
//specific implementation
}
};
struct less2
{
bool operator()(const SomeCutsomClass& c1, const SomeCutsomClass& c1)
{
//specific implementation
}
};
Ideally I should be able to pass the predicates somehow in the constructor of Heap
I am not able to visualize how to achieve this.
It is not that I want to use only predicates.Since I cant overload same operator twice in SomeCutsomClass , I am trying to use predicates.
I tried looking up STL source code of some well known data structures like std::sort etc , but they look complicated to me.
Here is an example containing both an example of std::less use and custom predicates as functions (lambdas).
#include <cassert>
#include <array>
#include <iostream>
#include <functional>
// Make heap a class template
// this allows you to specialize easily for any class
// I added the STL like third template parameter as example
// type_t is the type to store in the heap
// N is the size of the heap
template<typename type_t, std::size_t N, class Compare = std::less<type_t>>
class Heap
{
public:
using pred_t = std::function<bool(const type_t&, const type_t&)>;
Heap() :
m_predicate{ Compare() }
{
}
explicit Heap(pred_t predicate) :
m_predicate{ predicate }
{
}
bool compare(const int a, const int b)
{
return m_predicate(a, b);
}
private:
std::array<type_t, N> m_elements;
pred_t m_predicate;
};
struct SomeCustomClass
{
// all you need to make SomeCustomClass usable in Heap
// if it uses std::less as third template parameter
// is to provide this compare overload
bool operator<(const SomeCustomClass& other) const
{
return m_value < other.m_value;
}
int m_value{};
};
int main()
{
// this heap will use std::less
Heap<int, 100> less_heap;
assert(less_heap.compare(1, 2));
// create a lambda predicate
auto pred = [](const int& lhs, const int& rhs)
{
return lhs > rhs;
};
// this heap will use custom predciate
Heap<int, 100> greater_heap(pred);
assert(greater_heap.compare(2,1));
//
Heap<SomeCustomClass, 10> custom_heap;
return 0;
}
I have lots of code which creates a std::set<Port*>. Now by default this uses less<Port*> which sorts the set on pointer values. This creates problem in our tool. I want to provide a default comparator my_less for all set<Port*> without having to go and change all the code. So I tried template specialization :
namespace std {
template<> class set<Port*> : public set<Port*, my_less> {};
};
I put this code in a header file already included by all the code files. This works the way I expected that all set<Port*> are now using my_less. The problem is that such specialization is not inheriting constructors. So i get an error if I want to do this :
std::set<Port*> myset_new(myset1.begin(), myset1.end());
set.cpp:53:63: error: no matching function for call to
‘std::set<Port*>::set(std::set<Port*, znl_id_less>::iterator, std::set<Port*, my_less>::iterator)’
set_include.h:27:70: note: candidates are: std::set<Port*>::set()
set_include.h:27:70: note: std::set<Port*>::set(const std::set<Port*>&)
What is a good way to solve this (I can copy the code for constructors but that doesn't seem clean).
Is there any other way to achieve what I am trying to do apart from:
template<> class set<Port*> : public set<Port*, my_less> {};
Since C++11, you can inherit constructors easily with the using-declaration, like this:
namespace std {
template<> class set<Port*> : public set<Port*, my_less> {
public: using set<Port*, my_less>::set;
};
};
Here is my generic solutions to this problem
#include <set>
#include <functional>
#include <iostream>
// structs
struct my_struct
{
int a;
int b;
};
struct my_second_struct
{
int a;
int b;
};
bool operator<(const my_second_struct& m1, const my_second_struct& m2)
{
return m1.b < m2.b;
}
// alias helper
template <typename T>
using custom_comparator_t = std::function<bool(const T, const T)>;
// function to proxy already defined operator to pointers
template<typename T>
auto get_pointer_less()
{
return [](const T* v1, const T* v2) -> bool { return (*v1) < (*v2); };
}
// this is generic solution
template<typename T>
using pointer_set = std::set<T*, custom_comparator_t<T*>>;
// and final config
template<typename T>
auto get_pointer_set()
{
return pointer_set<T>( get_pointer_less<T>() );
}
template<typename T, typename _T>
void fill_and_display(_T& s)
{
s.insert(new T{10, 20});
s.insert(new T{20, 10});
s.insert(new T{0, 100});
s.insert(new T{100, 0});
std::cout << "set: ";
for (const T *ms : s)
std::cout << "( " << ms->a << " ; " << ms->b << " )";
std::cout << std::endl;
}
int main()
{
// First option, create custom less operator inline
std::set<my_struct *, custom_comparator_t<my_struct *>> myset(
[](const my_struct *ms1, const my_struct *ms2) { return ms1->a < ms2->a; }
);
fill_and_display<my_struct>(myset);
// Second option, reuse, already defined less operator
std::set<my_second_struct *, custom_comparator_t<my_second_struct*>> my_second_set(
get_pointer_less<my_second_struct>()
);
fill_and_display<my_second_struct>(my_second_set);
// generic colution for second set
auto my_third_set = get_pointer_set<my_second_struct>();
fill_and_display<my_second_struct>(my_third_set);
return 0;
}
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.
In general, templates arguments can be abstract classes, as the program below also shows. But it seems that the compare functor in sort must not be abstract. At least the following does not compile with VC++ 11 and on Oracle Studio 12.
#include <vector>
#include <algorithm>
class Functor
{
public:
virtual bool operator()(int a, int b) const = 0;
};
class MyFunctor: public Functor
{
public:
virtual bool operator()(int a, int b) const { return true; }
};
int _tmain(int argc, _TCHAR* argv[])
{
vector<Functor> fv; // template of abstract class is possible
vector<int> v;
MyFunctor* mf = new MyFunctor();
sort(v.begin(), v.end(), *mf);
Functor* f = new MyFunctor();
// following line does not compile:
// "Cannot have a parameter of the abstract class Functor"
sort(v.begin(), v.end(), *f);
return 0;
}
Now, I wonder whether this is a general property of functor arguments, or does it depend on the STL implementation? Is there a way to get, what I wanted to do?
Functors generally need to be copyable. Polymorphic base classes are generally not copyable, and abstract bases never.
Update: Thanks to the comments by #ahenderson and #ltjax, here's a very simple way to produce a wrapper object that holds your original, polymorphic reference:
#include <functional>
std::sort(v.begin(), v.end(), std::ref(*f));
// ^^^^^^^^^^^^
The result of std::ref is a std::refrence_wrapper which is exactly what you need: A class with value semantics that holds a reference to your original object.
The fact that functors get copied throws off lots of people who want to accumulate something inside the functor and then wonder why the results are off. The functor should really take a reference to an external object. To wit:
Bad! Won't work as you expect; the functor may get copied arbitrarily:
struct Func1 {
int i;
Func1() : i(0) { }
void operator()(T const & x) { /* ... */ }
};
Func1 f;
MyAlgo(myContainer, f);
Good: You provide the accumulator; it's safe to copy the functor:
struct Func2 {
int & i;
Func2(int & n) : i(n) { }
void operator()(T const & x) { /* ... */ }
};
int result;
MyAlgo(myContainer, Func2(result));
As Kerrek has said you can't do it directly:
But one level of indirection and you're OK.
struct AbstractFunctor
{
AbstractFunctor( Functor * in_f ): f(in_f) {}
// TODO: Copy constructor etc.
Functor * f;
bool operator()(int a, int b) const { return (*f)(a,b); }
};
int main()
{
vector<int> v;
Functor * mf = new MyFunctor();
sort(v.begin(), v.end(), AbstractFunctor(mf) );
}
As Kerrek and Michael Anderson said, you can't do it directly. As Michael shows, you can write a wrapper class. But there's also one in std:: :
sort(v.begin(),
v.end(),
std::bind(&Functor::operator(),
mf,
std::placeholders::_1,
std::placeholders::_2) );