this is probably a damn straightforward question. But I can't seem to insert my object into a map. I'm pretty sure I do not have to define my own copy constructor, as I solely using standard stuff. Feel like banging my head against a wall now :lol:, this is the map I am trying to create:
map<unsigned, Vertex> vertexes;
Header file of Vertex:
#ifndef KNOTSV2_VERTEX_H
#define KNOTSV2_VERTEX_H
#include <forward_list>
#include <set>
#include <iostream>
#include "VertexType.h"
using namespace std;
// Defines.
typedef tuple<edge_list, edge_list, edge_list> neigh_set_entry;
/*
* Matching
*/
struct match_first {
match_first(unsigned value) : value(value) {};
template<class A>
bool operator()(const pair<unsigned, A> &a) {
return a.first == value;
}
private:
unsigned value;
};
class Vertex {
public:
/*
* Constructors
*/
Vertex(unsigned identifier, VertexType *type, unsigned attributes) : identifier(identifier), type(type), values(attributes_vec(attributes)) {};
// Methods ..
private:
/*
* Members
*/
unsigned identifier;
attributes_vec values;
VertexType *type;
vector<pair<unsigned, neigh_set_entry>> neigh_set;
};
Function i am trying to call:
Vertex& Graph::create_vertex(VertexType &type) {
Vertex v(id_enumerator++, &type, type.num_attributes());
return vertexes[id_enumerator] = v;
}
note: in instantiation of member function 'std::__1::map, std::__1::allocator > >::operator[]' requested here
return vertexes[id_enumerator] = v;
^
note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 0 were provided
class Vertex {
^
note: candidate constructor (the implicit copy constructor) not viable:
note: candidate constructor not viable: requires 3 arguments, but 0 were provided
Vertex(unsigned identifier, VertexType *type, unsigned attributes) : identifier(identifier), type(type), values(attributes_vec(attributes)) {};
So I understand it is due to the fact that it tries to call the 'normal constructor', but I don't want to create getter and setters for the values am passing to the constructor; as they may not be changed. As a second attempt I tried to use map::emplace, but no luck there either. Is there any other option besides creating a normal constructor?
Tried emplace and insert and pairwise construct, no luck either.
Vertex& Graph::create_vertex(VertexType &type) {
//Vertex v();
return vertexes.insert(make_pair(id_enumerator, Vertex(id_enumerator, &type, type.num_attributes()))).first->second;
}
Vertex& Graph::create_vertex(VertexType &type) {
//Vertex v();
return vertexes.emplace(id_enumerator, Vertex(id_enumerator, &type, type.num_attributes())).first->second;
}
Vertex& Graph::create_vertex(VertexType &type) {
//Vertex v();
return vertexes.emplace(piecewise_construct, forward_as_tuple(id_enumerator), forward_as_tuple(id_enumerator, &type, type.num_attributes())).first->second;
}
Read std::map::emplace's documentation:
The constructor of the new element (i.e. std::pair<const Key, T>) is called with exactly the same arguments as supplied to emplace, forwarded via std::forward<Args>(args)....
struct Vertex
{
Vertex(unsigned identifier, int type, unsigned attributes) {}
};
int main()
{
std::map<unsigned, Vertex> vertexes;
// Vertex
// vvvvvvvvvvvvvvvvv
vertexes.emplace(0u, Vertex{0u, 1, 0u});
// ^^
// const unsigned
}
live wandbox example
Related
I'm developing this program to run Dijkstra's Algorithm with an heap implementation and I want it to be as versatile as it can be so I'm using function pointer in order to avoid code repetition. This is the error that it pops. I'm using the stl make_heap
"Type must use '.*' or '->*' to call pointer-to-member function in '__comp (...)', e.g. '(... ->* __comp) (...)' "heap.h C/C++ Problem
Here is Dijkstra's Algorithm:
void Graph::dijkstraAlg(Vertex* ini, Vertex* fin, void(Graph::*weight_filler)(void), bool(Graph::*pq_order)(const Vertex* &, const Vertex* &)){
for(unsigned int i = 0; i < vertexs.size(); i++) {
vertexs[i]->path = NULL;
vertexs[i]->holder = MAX_INT_VALUE;
vertexs[i]->processing=false;
}
(this->*weight_filler)();
Vertex* v=ini;
v->holder = 0;
v->processing = true;
vector<Vertex*> pq;
pq.push_back(v);
make_heap(pq.begin(),pq.end(),pq_order);
while(!pq.empty()){
v=pq.front();
pop_heap(pq.begin(),pq.end());
pq.pop_back();
for(unsigned int u=0; u < v->adj.size(); u++){
Vertex* w = v->adj[u]->dest;
if((v->holder+v->adj[u]->weight) < w->holder){
w->holder=v->holder + v->adj[u]->weight;
w->path=v;
if(!w->processing){
w->processing=true;
pq.push_back(w);
}
}
make_heap(pq.begin(),pq.end(),pq_order);
}
}
return;}
The error is in the make_heap and I can't figure it out, any help is appreciated.
Here is the function I'm passing to the make_heap:
bool Graph::regular_PqOrder(const Vertex* &v, const Vertex* &u){
return v->holder > u->holder;}
This is how I call the algo:
dijkstraAlg(i,f,&Graph::price_WeightFiller,&Graph::regular_PqOrder);
If you need more information just tell me and I edit it.
Thank you pal's
You're passing the wrong type. std::make_heap takes a functor as the third element, which should satisfy the requirements of Compare, which are that you need:
bool operator()(const Type1&, const Type2&) const;
You are passing in pq_order which is of type:
bool(Graph::*)(const Vertex* &, const Vertex* &)
That's a pointer-to-member, it's not callable without an object of type Graph. Hence the error about "Type must use '.' or '->' to call pointer-to-member". The simplest approach is to simply provide that object, which in your case is this:
using namespace std::placeholders;
std::make_heap(pq.begin(), pq.end(),
std::bind(pq_order, this, _1, _2));
Alternatively, since regular_PqOrder doesn't actually rely on any of the members of other methods of Graph, you could also just be to make it static:
class Graph {
public:
static bool regular_PqOrder(const Vertex* &v, const Vertex* &u)
{
return v->holder > u->holder;
}
};
And pass in Graph::regular_PqOrder now as a function pointer, rather than pointer-to-method.
I have simplified your problem to:
#include <algorithm>
#include <vector>
using namespace std;
class Vertex
{};
class Graph
{
public:
void dijkstraAlg(Vertex* ini, Vertex* fin, void(Graph::*weight_filler)(void),
bool(Graph::*pq_order)(const Vertex*, const Vertex*))
{
(this->*weight_filler)();
struct Comparator
{
private:
Graph* m_g;
bool(Graph::*m_fn)(const Vertex*, const Vertex*);
public:
Comparator(Graph* g, bool(Graph::*fn)(const Vertex*, const Vertex*)) : m_g(g), m_fn(fn)
{}
bool operator()(const Vertex* one, const Vertex* two) const
{
return (m_g->*m_fn)(one, two);
}
};
Comparator comparator(this, pq_order);
vector<Vertex*> pq;
std::make_heap(pq.begin(), pq.end(), comparator);
}
void weight_filler1()
{
}
bool pq_order1(const Vertex*, const Vertex*)
{
return false;
}
};
int main()
{
Graph g;
g.dijkstraAlg(nullptr, nullptr, &Graph::weight_filler1, &Graph::pq_order1);
return 0;
}
The problem is: std::make_heap expects a function pointer- in your case you are passing a pointer to member function thus the issue.
Either you can change the declaration of dijkstraAlg to take in just a static function pointer pq_order or wrap up pq_order in a structure to make it a callable entity in itself like I have done.
Note: you will have to fixup references to pointers in pq_order for make_heap to compile anyway
I am working in a graph class , and i have just started to build a class for vertex , and another class for edge , my question is general not related to graph.
first i build a class its name Vertex , i didn't face any problem in implementing it so far , then i started another class its name is Edge , Edge has three main members two of them has the type Vertex , and the third member has the type unsigned int.
here is the code :
#include<iostream>
using namespace std;
class Vertex
{
private:
unsigned int id;
public:
unsigned int get_id(){return id;};
void set_id(unsigned int value) {id = value;};
Vertex(unsigned int init_val) {id = init_val;};
~Vertex() {};
};
class Edge
{
private:
Vertex first_vertex; // a vertex on one side of the edge
Vertex second_vertex; // a vertex on the other side of the edge
unsigned int weight; // the value of the edge ( or its weight )
public:
Edge(Vertex vertex_1, Vertex vertex_2, unsigned int init_weight) //constructor
{
first_vertex(vertex_1.get_id());
second_vertex(vertex_2.get_id());
weight = init_weight;
}
~ Edge(); // destructor
};
///////////////////////////////// this part is to test the result
Vertex ver_list[2] = {7, 9};
Vertex test = 101;
int main()
{
cout<< "Hello, This is a graph"<< endl;
for (unsigned int i = 0; i < 2; i++) cout<< ver_list[i].get_id() << endl;
cout<< test.get_id() << endl;
return 0;
}
before adding the constructor Edge the code was running without errors , after adding the constructor Edge i received errors when trying to run the code , i am not able to determine my mistake above .
Thanks for your suggestions.
here is the errors message i am receiving:
hw2.cpp: In constructor 'Edge::Edge(Vertex, Vertex, unsigned int)':
hw2.cpp:31:6: error: no matching function for call to 'Vertex::Vertex()'
{
^
hw2.cpp:31:6: note: candidates are:
hw2.cpp:13:2: note: Vertex::Vertex(unsigned int)
Vertex(unsigned int init_val) {id = init_val;}; // constructor
^
hw2.cpp:13:2: note: candidate expects 1 argument, 0 provided
hw2.cpp:6:7: note: Vertex::Vertex(const Vertex&)
class Vertex
^
hw2.cpp:6:7: note: candidate expects 1 argument, 0 provided
hw2.cpp:31:6: error: no matching function for call to 'Vertex::Vertex()'
{
^
hw2.cpp:31:6: note: candidates are:
hw2.cpp:13:2: note: Vertex::Vertex(unsigned int)
Vertex(unsigned int init_val) {id = init_val;}; // constructor
^
hw2.cpp:13:2: note: candidate expects 1 argument, 0 provided
hw2.cpp:6:7: note: Vertex::Vertex(const Vertex&)
class Vertex
^
hw2.cpp:6:7: note: candidate expects 1 argument, 0 provided
hw2.cpp:32:41: error: no match for call to '(Vertex) (unsigned int)'
first_vertex(vertex_1.get_id());
^
hw2.cpp:33:42: error: no match for call to '(Vertex) (unsigned int)'
second_vertex(vertex_2.get_id());
Maybe the problem is the syntax in your constructor:
Edge(Vertex vertex_1, Vertex vertex_2, unsigned int init_weight) //constructor
{
first_vertex(vertex_1.get_id());
second_vertex(vertex_2.get_id());
weight = init_weight;
}
You should initialize the members in an initializer list.
Edge(Vertex vertex_1, Vertex vertex_2, unsigned int init_weight) : first_vertex(vertex_1.get_id()), second_vertex(vertex_2.get_id()), weight(init_weight)
{
}
and you should pass const references to Vertex:
Edge(const Vertex& vertex_1, const Vertex& vertex_2, unsigned int init_weight)
hw2.cpp:32:41: error: no match for call to '(Vertex) (unsigned int)'
first_vertex(vertex_1.get_id());
That error message is addressed below:
Edge(const Vertex& vertex_1, const Vertex& vertex_2, unsigned int init_weight) //constructor
: first_vertex(vertex_1.get_id()), second_vertex(vertex_2.get_id()), weight(init_weight)
{
}
You were trying to initialize your vertexes using their constructors inside the Edge constructor's body (instead of in it's initializer list). That is not valid syntax. You would either need to use the initializer list (show, and preferred), or use their assignment operator in the body of the constructor (syntactically correct, but not preferred as the Vertex would be constructed with incorrect data, and then initialized, instead of simply constructed with the correct data).
An even better approach would be to utilize the copy-constructor of Vertex (instead of your conversion constructor):
// notice the lack of calling the get_id function
Edge(const Vertex& vertex_1, const Vertex& vertex_2, unsigned int init_weight)
: first_vertex(vertex_1), second_vertex(vertex_2), weight(init_weight)
{
}
Additionally, with the following error message:
hw2.cpp:31:6: error: no matching function for call to 'Vertex::Vertex()
You have declared a non-default, non-copy-constructor ( Vertex(unsigned int init_val)), so the compiler will not generate a default constructor for you. Since it will try to initialize a Vertex with the default constructor when you attempt to initialize first_vertex and second_vertex in the body of the Edge constructor, and it does not exist, you get an error. You can fix that by declaring a Vertex() {} constructor.
Probably this is the fix:
Edge(Vertex vertex_1, Vertex vertex_2, unsigned int init_weight) //constructor
{
first_vertex = Vertex(vertex_1.get_id());
second_vertex = Vertex(vertex_2.get_id());
weight = init_weight;
}
You are trying to set your vertex values in edge the wrong way. Use something like
first_vertex.set_id(vertex_1.get_id());
Also, there are standard representations for this type of problem. See more here: http://en.wikipedia.org/wiki/Graph_%28abstract_data_type%29#Representations
I am having trouble trying to insert a std::pair in the std::vector, with this code:
template <class R>
class AVectorContainner
{
public:
AVectorContainner()
{
mVector= new std::vector<entry>;
}
typedef std::pair<int ,R *> entry;
void insert(R* aPointer, int aID)
{
entry aEntry;
aEntry=std::make_pair(aID,aPointer );
mVector->push_back(aEntry);
}
private:
std::vector<entry> * mVector;
}
This is the part of the main file, that I declare a pointer of a class and then I used it in the initialization of the template class.
In the main.cpp:
int main()
{
SomeType * aTipe= new SomeType;
int aID=1;
AVectorContainer<SomeType> * aContainer= new AVectorContainer;
aContainer->insert(aTipe,aId);//error line
delete aTipe;
delete aContainer;
return 0;
}
Compiler Output:
error: non-static reference member 'const int& std::pair<const int&, SomeType *>::first', can't use default assignment operator
error: value-initialization of reference type 'const int&'
The original poster failed to actually post the code that was causing the problem.
He has since edited my post with the correct code that demonstrates the problem. The code that demonstrates the problem follows:
template <class R, typename B=int>
class AVectorContainer
{
public:
AVectorContainer() {}
typedef R* ptr_Type;
typedef const B & const_ref_Type;
typedef std::pair<const_ref_Type ,ptr_Type> entry;
void insert(ptr_Type aPointer, const_ref_Type aID) {
entry aEntry=std::make_pair(aID,aPointer);
mVector.push_back(aEntry);
}
private:
std::vector<entry> mVector;
};
class SomeType
{
public:
SomeType(){ x=5; }
~SomeType(){ }
int x;
};
int main()
{
SomeType * aTipe= new SomeType;
int aID=1;
AVectorContainer<SomeType> aContainer;
aContainer.insert(aTipe,aID);
return 0;
}
Compiler output:
/usr/include/c++/4.7/bits/stl_pair.h:88: error: non-static reference member 'const int& std::pair<const int&, SomeType*>::first', can't use default assignment operator
The flaw is in these lines:
typedef R* ptr_Type;
typedef const B & const_ref_Type;
typedef std::pair<const_ref_Type ,ptr_Type> entry;
std::vector<entry> mVector;
Here, the original poster attempts to make a vector of pairs that contain a constant reference, and then does this:
entry aEntry;
aEntry=std::make_pair(aID,aPointer )
this attempts to assign one pair to another. But const& variables cannot be assigned to another -- they can be constructed (initialized) from another const&, but not assigned.
An easy fix is:
entry aEntry=std::make_pair(aID,aPointer )
so that we are not constructing aEntry from another entry, instead of default constructing aEntry (which is also illegal: const& must be initialized), then assigning to it.
Fixed all typos, compare the two ... he did like 100 in 20 lines!
#include <vector>
#include <utility>
template <class R>
class AVectorContainer
{
public:
AVectorContainer()
{
mVector= new std::vector<entry>;
}
typedef std::pair<int ,R *> entry;
void insert(R* aPointer, int aID)
{
entry aEntry;
aEntry=std::make_pair(aID,aPointer );
mVector->push_back(aEntry);
}
private:
std::vector<entry> * mVector;
};
class SomeType
{
public:
SomeType(){ x=5; }
~SomeType(){ }
int x;
};
int main()
{
SomeType * aTipe= new SomeType;
int aID=1;
AVectorContainer<SomeType> * aContainer= new AVectorContainer<SomeType>;
aContainer->insert(aTipe,aID);//error line
return 0;
}
After fixing all the typo's (Containner, aId, missing ; etc.) the code compiles just fine.
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
}
I have this a class called 'Card' and I am trying to store some of its objects in a std::map
Card.hpp:
class Card
{
public:
enum ValueType { NOVALUE, ACE };
enum FaceType { NOFACE, CLUBS };
Card(const ValueType & _value, const FaceType & _face);
Card(const Card & _card);
private:
ValueType m_value;
FaceType m_face;
};
Here is how I store and access it:
Deck.hpp:
#include <map>
class Card;
class Deck
{
public:
Deck();
std::size_t length() const;
Card get_card(const int & _num);
private:
std::map<int, Card> m_deck;
};
Deck.cpp:
#include "Card.hpp"
Deck::Deck()
{
m_deck.insert(std::pair<int, Card>(0, Card(Card::NOVALUE, Card::NOFACE)));
m_deck.insert(std::pair<int, Card>(1, Card(Card::ACE, Card::CLUBS)));
}
std::size_t Deck::length() const
{
return m_deck.size();
}
Card Deck::get_card(const int & _num)
{
return m_deck[_num];
}
Now, when I compile it I get following error:
/usr/include/c++/4.6/bits/stl_map.h:453:45: error: no matching constructor for initialization of 'mapped_type' (aka 'Card')
__i = insert(__i, value_type(__k, mapped_type()));
^
Deck.cpp:69:18: note: in instantiation of member function 'std::map<int, Card, std::less<int>, std::allocator<std::pair<const int, Card> > >::operator[]' requested here
return m_deck[_num];
^
./Card.hpp:30:2: note: candidate constructor not viable: requires 2 arguments, but 0 were provided
Card(const ValueType & _value, const FaceType & _face);
^
./Card.hpp:32:2: note: candidate constructor not viable: requires 1 argument, but 0 were provided
Card(const Card & _card);
^
1 error generated.
Why am I getting this error? I am using Card only as a value!
The problem is that for a map, m_deck[_num] is designed to insert a default constructed Card if the element isn't already there. And Card doesn't have a default constructor.
You can use map::find to see if the entry is there, without creating one.
For Deck::get_card() to compile, Card needs to provide a default constructor (presumably initializing the object to Card::NOVALUE, Card::NOFACE).
The reason for that is that m_deck[_num] returns a default-constructed instance of Card is _num is not in the map.