How to set and get graph property from boost graph library? - boost

I don't know how to set and get graph_name as property from adjacency_list graph. I am able to put and get vertex and edge properties.
Any help would be appreciated.

First thing is to define classes to hold the properties for vertex, edge and graph
class cVertexProps {
...
}
class cEdgeProps {
...
}
class cGraphProps {
public:
std::string myName;
...
};
Now define your graph
typedef boost::adjacency_list <
boost::vecS, boost::vecS, boost::undirectedS,
cVertexProps, cEdgeProps, cGraphProps >
graph_t;
graph_t myGraph;
... and so set your graph name
myGraph[graph_bundle].myName= "My First Graph";
This uses "bundled properties", which are described here: http://www.boost.org/doc/libs/1_55_0/libs/graph/doc/bundles.html

I have solution for boost subgraph(just try it for graph it will work for sure) property get and set as below:-
#include <QtCore/QCoreApplication>
#include <boost/config.hpp>
#include <iostream>
#include <algorithm>
#include <boost/graph/adjacency_list.hpp>
#include <boost/property_map/property_map.hpp>
#include <string>
#include <boost/graph/subgraph.hpp>
#include <QMap>
using namespace std;
using namespace boost;
enum graph_IDproperty_t
{
graph_IDproperty
};
namespace boost
{
BOOST_INSTALL_PROPERTY(graph,IDproperty);
}
struct GraphProperties {
std::string strName;
std::string id;
};
typedef boost::subgraph<
boost::adjacency_list<
boost::listS, boost::vecS, boost::bidirectionalS,
boost::property<boost::vertex_index_t, int,
property< boost::vertex_color_t, boost::default_color_type > >,
boost::property<boost::edge_index_t, int,
property<boost::edge_color_t, default_color_type> >,
boost::property<graph_IDproperty_t,GraphProperties>
>
> Graph;
Graph gMainGraph;
typedef QMap<Graph*,GraphProperties*> mapGraphToProperty;
mapGraphToProperty getMap(Graph& graph);
void graphMapRecur(mapGraphToProperty& map, Graph& graph);
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Graph& subG = gMainGraph.create_subgraph();
Graph& subG1 = gMainGraph.create_subgraph();
boost::ref_property_map<Graph*, GraphProperties>
graph_propt1(boost::get_property(subG1,graph_IDproperty));
graph_propt1[&subG1].id = "SubG1";
cout << graph_propt1[&subG1].id << endl;
boost::ref_property_map<Graph*, GraphProperties>
graph_propt(boost::get_property(subG,graph_IDproperty));
graph_propt[&subG].id = "SubG";
cout << graph_propt[&subG].id << endl;
boost::ref_property_map<Graph*, GraphProperties>
graph_proptMain(boost::get_property(gMainGraph,graph_IDproperty));
graph_proptMain[&gMainGraph].id = "gMain";
cout << graph_proptMain[&gMainGraph].id << endl;
mapGraphToProperty map = getMap(gMainGraph);
boost::ref_property_map<Graph*, GraphProperties>
graph_proptMain1(*(map.value(&gMainGraph)));
boost::ref_property_map<Graph*, GraphProperties>
graph_proptsubG(*(map.value(&subG)));
boost::ref_property_map<Graph*, GraphProperties>
graph_proptsubG1(*(map.value(&subG1)));
cout << "Main G Value : " << graph_proptMain1[&gMainGraph].id << endl;
cout << "Sub G Value : " << graph_proptsubG[&subG].id << endl;
cout << "Sub G1 Value : " << graph_proptsubG1[&subG1].id << endl;
cout << "Map Value Main: " << (map.value(&gMainGraph)) << endl;
cout << "Map Value SubG: " << (map.value(&subG)) << endl;
cout << "Map Value SubG1b: " << (map.value(&subG1)) << endl;
return a.exec();
}
mapGraphToProperty getMap(Graph &graph)
{
mapGraphToProperty map;
graphMapRecur(map,graph);
return map;
}
void graphMapRecur(mapGraphToProperty &map, Graph &graph)
{
Graph::children_iterator itrSubgraph, itrSubgraph_end;
for (boost::tie(itrSubgraph, itrSubgraph_end) = (graph).children();
itrSubgraph != itrSubgraph_end; ++itrSubgraph)
{
graphMapRecur(map,(*itrSubgraph));
}
GraphProperties* gp = &(get_property(graph,graph_IDproperty));
map.insert(&graph,gp);
cout << "Recurrr" << endl;
}

Related

MultiIndex Container equal_range .. get output in reverse order

I have a boost::multiIndex container.
say :
typedef boost::multi_index<....
> OrderSet;
OrderSet orderSet_;
int main()
{
const auto it = orderSet_.get<0>().equal_range(boost::make_tuple(/* Some Values*/))
if(it.first != it.second)
while(it.second != it.first) { /* Somethings to do */;
--it.second;
}
}
the program crash with offset_ptr error.
for the program it has value on increasing order. so I want highest value first then so-on..
Is any a over-loaded function of boost::equal_range(..., [&](const auto a, const auto b)-> decltype bool{return a > b;});
Something like this. it's like reverse_iterator of equal_range()
UPDATE: multi-Index container is accessed by one producer and many consumer. while consumer is finding equal_range, producer add or delete elements and consumer throw the error... this is only happens when i am reverse iterating...
You're leaving out the essential part: the chosen index type.
Different index types afford different interfaces.
Then again, equal_range implies a ordered or unordered map. And because reversing the order on an unordered map is non-sense, I'm going to assume an ordered map.
Next, with make_tuple there I'm guessing composite keys.
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/composite_key.hpp>
struct X {
int i;
std::string name;
};
namespace bmi = boost::multi_index;
typedef boost::multi_index_container<X,
bmi::indexed_by<
bmi::ordered_non_unique<
bmi::tag<struct by_i>,
bmi::composite_key<X,
bmi::member<X, int, &X::i>,
bmi::member<X, std::string, &X::name>
>
>
>
> OrderSet;
Then here's the native order:
#include <iostream>
int main()
{
std::cout << std::unitbuf;
OrderSet orderSet_ {
{ 1, "one" }, { 1, "two" }, { 2, "three" }, { 3, "four" }, { 2, "five" }
};
auto const range = orderSet_/*.get<0>()*/.equal_range(boost::make_tuple(2));
for (auto& el : boost::make_iterator_range(range))
std::cout << el.i << "," << el.name << "; ";
// ...
And I'd use Boost Range to get the reverse order:
#include <boost/range/adaptor/reversed.hpp>
// ...
// traverse these in reverse
std::cout << "\nNow in reverse:\n";
for (auto& el : range | boost::adaptors::reversed)
std::cout << el.i << "," << el.name << "; ";
}
BONUS TAKE
Of course you can write the same manually:
std::cout << "\nAlso in reverse:\n";
auto it = orderSet_.get<0>().equal_range(boost::make_tuple(2));
while(it.second != it.first) {
--it.second;
auto& el = *it.second;
std::cout << el.i << "," << el.name << "; ";
}
Live Demo
Live On Coliru
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/range/adaptor/reversed.hpp>
struct X {
int i; // = [] { static int gen = 0; return ++gen; }();
std::string name;
};
namespace bmi = boost::multi_index;
typedef boost::multi_index_container<X,
bmi::indexed_by<
bmi::ordered_non_unique<
bmi::tag<struct by_i>,
bmi::composite_key<X,
bmi::member<X, int, &X::i>,
bmi::member<X, std::string, &X::name>
>
>
>
> OrderSet;
#include <iostream>
int main()
{
std::cout << std::unitbuf;
OrderSet orderSet_ {
{ 1, "one" }, { 1, "two" }, { 2, "three" }, { 3, "four" }, { 2, "five" }
};
{
auto const range = orderSet_/*.get<0>()*/.equal_range(boost::make_tuple(2));
for (auto& el : boost::make_iterator_range(range))
std::cout << el.i << "," << el.name << "; ";
// traverse these in reverse
std::cout << "\nNow in reverse:\n";
for (auto& el : range | boost::adaptors::reversed)
std::cout << el.i << "," << el.name << "; ";
}
{
std::cout << "\nAlso in reverse:\n";
auto it = orderSet_.get<0>().equal_range(boost::make_tuple(2));
while(it.second != it.first) {
auto& el = *(--it.second);
std::cout << el.i << "," << el.name << "; ";
}
}
}
Prints
2,five; 2,three;
Now in reverse:
2,three; 2,five;
Also in reverse:
2,three; 2,five;
Even further out on a limb, since you said offset_ptr you might be using Boost Interprocess allocators.
Here's a demo that shows how you'd do the above correctly in a memory mapped/shared memory area:
Live On Coliru
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
namespace bmi = boost::multi_index;
namespace bip = boost::interprocess;
//namespace Shared { struct X; }
//namespace std { template<typename Alloc> struct uses_allocator<Shared::X, Alloc> : std::true_type {}; }
namespace Shared {
using Segment = bip::managed_mapped_file;
template <typename T> using Alloc = bip::allocator<T, Segment::segment_manager>;
using String = boost::interprocess::basic_string<char, std::char_traits<char>, Alloc<char> >;
struct X {
using allocator_type = Alloc<char>;
template <typename Alloc>
X(int i, std::string const& s, Alloc alloc) : i(i), name(s.begin(), s.end(), alloc) {}
int i;
String name;
};
typedef boost::multi_index_container<X,
bmi::indexed_by<
bmi::ordered_non_unique<
bmi::tag<struct by_i>,
bmi::composite_key<X,
bmi::member<X, int, &X::i>,
bmi::member<X, String, &X::name>
>
>
>,
Alloc<X>
> OrderSet;
}
#include <iostream>
int main()
{
std::cout << std::unitbuf;
Shared::Segment mmf(bip::open_or_create, "test.data", 10u << 10);
auto& orderSet_ = *mmf.find_or_construct<Shared::OrderSet>("set")(mmf.get_segment_manager());
if (orderSet_.empty()) {
// can't get multi-index to use the scoped allocator "magically" :(
orderSet_.emplace(1, "one", orderSet_.get_allocator());
orderSet_.emplace(1, "one", orderSet_.get_allocator());
orderSet_.emplace(1, "two", orderSet_.get_allocator());
orderSet_.emplace(2, "three", orderSet_.get_allocator());
orderSet_.emplace(3, "four", orderSet_.get_allocator());
orderSet_.emplace(2, "five", orderSet_.get_allocator());
}
{
auto const range = orderSet_/*.get<0>()*/.equal_range(boost::make_tuple(2));
for (auto& el : boost::make_iterator_range(range))
std::cout << el.i << "," << el.name << "; ";
// traverse these in reverse
std::cout << "\nNow in reverse:\n";
for (auto& el : range | boost::adaptors::reversed)
std::cout << el.i << "," << el.name << "; ";
}
{
std::cout << "\nAlso in reverse:\n";
auto it = orderSet_.get<0>().equal_range(boost::make_tuple(2));
while(it.second != it.first) {
auto& el = *(--it.second);
std::cout << el.i << "," << el.name << "; ";
}
}
std::cout << "\nBye\n";
}
Prints
2,five; 2,three;
Now in reverse:
2,three; 2,five;
Also in reverse:
2,three; 2,five;
Bye
Twice (proving all data was correctly in the shared memory segment).
BONUS TAKE
Apparently, Boost Multi-Index doesn't quite play completely well with the scoped allocator, because it would be more elegant with that:
Live On Coliru
#include <set>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/container/set.hpp>
#include <boost/container/scoped_allocator.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <boost/range/iterator_range.hpp>
namespace bip = boost::interprocess;
namespace Shared {
using Segment = bip::managed_mapped_file;
template <typename T> using Alloc = bip::allocator<T, Segment::segment_manager>;
using String = boost::interprocess::basic_string<char, std::char_traits<char>, Alloc<char> >;
struct X {
using allocator_type = Alloc<char>;
template <typename Alloc>
X(int i, std::string const& s, Alloc alloc) : i(i), name(s.begin(), s.end(), alloc) {}
bool operator<(X const& other) const { return i < other.i; }
bool operator<(int other) const { return i < other; }
int i;
String name;
};
template <typename T>
using Multiset = boost::container::multiset<
T,
std::less<T>,
boost::container::scoped_allocator_adaptor<Alloc<X> >
>;
using OrderSet = Multiset<X>;
}
#include <iostream>
int main()
{
std::cout << std::unitbuf;
Shared::Segment mmf(bip::open_or_create, "test.data", 10u << 10);
auto& orderSet_ = *mmf.find_or_construct<Shared::OrderSet>("set")(mmf.get_segment_manager());
if (orderSet_.empty()) {
// scoped-allocator automatically propagates to the string
orderSet_.emplace(1, "one");
orderSet_.emplace(1, "one");
orderSet_.emplace(1, "two");
orderSet_.emplace(2, "three");
orderSet_.emplace(3, "four");
orderSet_.emplace(2, "five");
}
{
auto const range = orderSet_.equal_range({2, "", orderSet_.get_allocator()});
for (auto& el : boost::make_iterator_range(range))
std::cout << el.i << "," << el.name << "; ";
// traverse these in reverse
std::cout << "\nNow in reverse:\n";
for (auto& el : range | boost::adaptors::reversed)
std::cout << el.i << "," << el.name << "; ";
}
{
std::cout << "\nAlso in reverse:\n";
auto it = orderSet_.equal_range({2, "", orderSet_.get_allocator()});
while(it.second != it.first) {
auto& el = *(--it.second);
std::cout << el.i << "," << el.name << "; ";
}
}
std::cout << "\nBye\n";
}

boost spirit debug rule with locals

I fail to compile code in debug mode (code with BOOST_SPIRIT_DEBUG_NODE(my_rule)) when my_rule has some local variable of custom type.
First version with rule qi::locals<std::string> is OK
Second version with rule qi::locals<std::string,int> is still OK
Current version with rule qi::locals<std::string,std::vector<int> > does not compile.
error: no match for operator<< (operand types are std::basic_ostream<char> and const std::vector<int>)
I declare streaming operator<< :
std::ostream& > operator<< (std::ostream& os, std::vector<int> const& art)
But It still does not compile.
I use boost 1_64_0. Here is the smallest complete code:
#define BOOST_SPIRIT_DEBUG
#if !defined(BOOST_SPIRIT_DEBUG_OUT)
#define BOOST_SPIRIT_DEBUG_OUT std::cerr
#endif
#include <tuple>
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <iostream>
#include <string>
#include <vector>
// To solve the pb of declaration of grammar with locals
#include <typeinfo>
std::ostream&
operator<< (std::ostream& os, std::vector<int> const& art)
{
os << "[";
for( auto it = art.begin(); it != art.end() ; it++ ) {
os << *it << ",";
}
os << "]";
return os;
}
namespace client
{
namespace phoenix = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
using phoenix::val;
using namespace qi::labels;
using qi::_val;
using qi::_1;
// Our number list parser
template <typename Iterator>
struct mini_wkart_grammar
// first version: : qi::grammar<Iterator, int(), qi::locals<std::string>, ascii::space_type>
// second version: : qi::grammar<Iterator, int(), qi::locals<std::string,int>, ascii::space_type>
: qi::grammar<Iterator, std::vector<int>(), qi::locals<std::string,std::vector<int> >, ascii::space_type>
{
mini_wkart_grammar() : mini_wkart_grammar::base_type(start,"numbers")
{
using phoenix::push_back;
// first version: start= (qi::int_ >> qi::char_(',') >> qi::int_)[_val=_1+_3];
// second version: start= (qi::int_[_b=_1] >> qi::char_(',') >> qi::int_[_b+=_1])[_val=_b];
start= (qi::int_[push_back(_b,_1)] >> qi::char_(',') >> qi::int_[push_back(_b,_1)])[_val=_b];
BOOST_SPIRIT_DEBUG_NODE(start);
}
// first version OK: qi::rule<Iterator, int(), qi::locals<std::string>, ascii::space_type> start;
// second version OK: qi::rule<Iterator, int(), qi::locals<std::string,int>, ascii::space_type> start;
qi::rule<Iterator, std::vector<int>(), qi::locals<std::string,std::vector<int> >, ascii::space_type> start;
};
}
////////////////////////////////////////////////////////////////////////////
// Main program
////////////////////////////////////////////////////////////////////////////
int
main()
{
std::cout << "/////////////////////////////////////////////////////////\n\n";
std::cout << "\t\tA comma separated list parser for Spirit...\n\n";
std::cout << "/////////////////////////////////////////////////////////\n\n";
std::cout << "Give me a comma separated list of numbers.\n";
std::cout << "Type [q or Q] to quit\n\n";
// std::string result;
// first ans second version: int result;
std::vector<int> result;
std::string str;
using boost::spirit::ascii::space;
client::mini_wkart_grammar<std::string::const_iterator> wkart_grammar;
while (getline(std::cin, str))
{
if (str.empty() || str[0] == 'q' || str[0] == 'Q')
break;
std::string::const_iterator iter = str.begin();
std::string::const_iterator end = str.end();
// if (client::parse_numbers(str.begin(), str.end()))
if (boost::spirit::qi::phrase_parse(iter, end, wkart_grammar, space, result))
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
std::cout << result << " Parses OK: " << std::endl;
}
else
{
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "-------------------------\n";
}
}
std::cout << "Bye... :-) \n\n";
return 0;
}
I think miss something in the operator declaration?
Thanks for any help..
First Off...
What are you trying to achieve anyways? That whole grammar could be start = qi::int_ % ','; and still have the exact same effect. See Boost Spirit: “Semantic actions are evil”?
Your Question:
Sadly you need to make that operator<< ADL-enabled. (http://en.cppreference.com/w/cpp/language/adl)
Since the element type is primitive, there is no associated namespace. So the only namespace that will be tried is namespace ::std which declared std::vector<>.
namespace std {
std::ostream &operator<<(std::ostream &os, vector<int> const &art) {
os << "[";
for (auto it = art.begin(); it != art.end(); it++) {
os << *it << ",";
}
os << "]";
return os;
}
}
That might have undesired side effects, you you may want to force the issue with a hack:
namespace ADL_Hack {
template <typename T>
struct allocator : std::allocator<T> { };
}
template <typename T>
using Vector = std::vector<T, ADL_Hack::allocator<T> >;
namespace ADL_Hack {
template <typename... Ts>
std::ostream &operator<<(std::ostream &os, std::vector<Ts...> const &art) {
os << "[";
for (auto it = art.begin(); it != art.end(); it++) {
os << *it << ",";
}
os << "]";
return os;
}
}
See it Live On Wandbox

How to keep all properties of graph read by boost::read_graphviz?

Suppose you want to read in a .dot graph into boost where there could be properties you do not recognize. It is easy to ignore them (by passing ignore_other_properties to the dynamic_properties constructor) but what if you wanted all the properties added to dynamic_properties instead?
The below code demonstrates the problem. The handle_custom_properties is a copy of ignore_other_properties and the code will compile / run, reporting "3 vertices, 2 edges." What needs to be added to handle_custom_properties so that, on return, dp will contain a property "label" and node A will have value "x" for the label property?
#include <iostream>
#include <string>
#include <boost/graph/graphviz.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/exception/exception.hpp>
#include <boost/exception/diagnostic_information.hpp>
struct vertex_p {
std::string node_id;
};
typedef boost::adjacency_list < boost::vecS, boost::vecS, boost::undirectedS, vertex_p> graph_t;
boost::shared_ptr<boost::dynamic_property_map>
handle_custom_properties(const std::string& s,
const boost::any& k,
const boost::any& v) {
// What goes in here to add dynamic property map for property "s" which key-value pair <k,v>?
// What ignore_other_properties does
return boost::shared_ptr<boost::dynamic_property_map>();
}
int main() {
std::string str(R"(graph {
A [ label="x" ]
B
C
A -- B
A -- C
}
)");
try {
graph_t g;
boost::dynamic_properties dp{handle_custom_properties};
dp.property("node_id", get(&vertex_p::node_id, g));
if (boost::read_graphviz(str, g, dp)) {
std::cout << "read_graphviz returned success" << std::endl;
std::cout << "graph stats:" << std::endl;
std::cout << " " << g.m_vertices.size() << " vertices" << std::endl;
std::cout << " " << g.m_edges.size() << " edges" << std::endl;
}
else {
std::cout << "read_graphviz returned failure" << std::endl;
}
}
catch (std::exception& e) {
std::cerr << e.what() << std::endl;
}
catch (boost::exception& e) {
std::cerr << boost::diagnostic_information(e) << std::endl;
}
}
I was not able to find an existing class to solve this but implementing a dynamic_property_map in terms of a std::map worked:
template<typename TKey, typename TValue>
class dynamic_property_map_impl : public boost::dynamic_property_map {
std::map<TKey, TValue> map_;
public:
boost::any get(const boost::any& key) override { return map_[boost::any_cast<TKey>(key)]; }
std::string get_string(const boost::any& key) override { std::ostringstream s; s << map_[boost::any_cast<TKey>(key)]; return s.str(); }
void put(const boost::any& key, const boost::any& value) override { map_[boost::any_cast<TKey>(key)] = boost::any_cast<TValue>(value); }
const std::type_info& key() const override { return typeid(TKey); }
const std::type_info& value() const override { return typeid(TValue); }
};
boost::shared_ptr<boost::dynamic_property_map>
handle_custom_properties(const std::string&,
const boost::any&,
const boost::any&) {
return boost::make_shared<dynamic_property_map_impl<unsigned, std::string>>();
}
Changing the graph and printing out the properties shows all the property maps were added:
std::string str(R"(graph {
A [ label="x", stuff="y" ]
B
C [ happy="yes" ]
A -- B
A -- C
}
)");
...
std::cout << "properties:" << std::endl;
for (const auto& p : dp) {
std::cout << " " << p.first << std::endl;
}
Outputs
read_graphviz returned success
graph stats:
3 vertices
2 edges
properties:
happy
label
node_id
stuff

.compare not matching a string pulled from an object

I am trying to go threw a vector of Student objects. If I find a matching ID to the one I am searching for it will display their info.
However, when I try to find a specific ID .compare isn't seeing a match even though it should.
My output: first line is the ID I am looking for, second is the current ID being looked at, then is the result of the compare.
a11111111
a22222222
-1
no match
a11111111
a11111111
-1
no match
Asked for more of the code so here is the entire program: (issue in displayID)
header file
#ifndef structures_h
#define structures_h
#include <vector>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <fstream>
#include <sstream>
#include <string>
#include <algorithm>
#include <stdio.h>
#include <map>
using namespace std;
main program
#endif
typedef pair<string, string> Name; // first name, last name
typedef map<string, int> Grades; // map courses to scores
#include "struct.h"
class Student {
public:
void display(ostream& os) const;
void setId(string);
void setName(string, string);
void setGrades(string, int);
string getId();
string getName();
void getGrades();
bool operator<(const Student &rhs) const { return id_ < rhs.id_; }
private:
string id_; // e.g. "a22222222"
Name name_; // e.g. {"ned", "flanders"}
Grades grades_;
};
void Student::setId(string id) {
id_ = id;
}
string Student::getId() {
return id_;
}
void Student::setName(string first, string last) {
name_ = pair<string,string>(first, last);
}
string Student::getName() {
return get<0>(name_) + ' ' + get<1>(name_);
}
void Student::setGrades(string course, int score) {
grades_.insert(make_pair(course, score));
}
void Student::getGrades() {
for(auto it = grades_.begin(); it != grades_.end(); ++it) {
cout << it -> first << ' ' << it -> second << endl;
}
}
vector<Student> addStudent(int count, int x, vector<Student>& vStu, string file) {
string line, first, last;
ifstream infile(file);
while (getline(infile, line)) {
vStu.push_back(Student());
vStu[count].setId(line);
getline(infile, line);
istringstream iss(line);
if (!(iss >> first >> last)) {
cout << "failed to get name" << endl;
break;
}
vStu[count].setName(first, last);
getline(infile, line);
istringstream iss2(line);
if (!(iss2 >> x)) {
cout << "failed to get class number" << endl;
break;
}
for (int i = 0; i < x; i++) {
string sClass;
int grade;
getline(infile, line);
istringstream iss3(line);
if (!(iss3 >> sClass >> grade)) {
cout << "failed to get class and grade" << endl;
break;
}
vStu[count].setGrades(sClass, grade);
}
count++;
}
return vStu;
}
void display(vector<Student>& vStu) {
sort(vStu.begin(), vStu.end());
cout << endl;
int count = vStu.size();
for (int i = 0; i<count;i++) {
cout << vStu[i].getId() << endl;
cout << vStu[i].getName() << endl;
vStu[i].getGrades();
cout << endl;
}
}
void displayID(vector<Student>& vStu, string ID) {
int count = vStu.size();
string test;
ID = "a11111111";
for (int i = 0; i<count;i++) {
cout<< endl;
test = vStu[i].getId();
cout << ID << endl;
cout << test << endl;
cout << ID.compare(test) << endl;
if (ID.compare(test) == 0) {
cout << "match" << endl;
cout << vStu[i].getId() << endl;
cout << vStu[i].getName() << endl;
vStu[i].getGrades();
cout << endl;
} else {
cout << "no match" << endl;
}
}
cout << endl;
}
void mainMenu(vector<Student>& vStu) {
string input;
string word;
vector<string> com;
while(1) {
cout << "Enter command: ";
getline(cin,input);
istringstream iss(input);
while(iss >> word) {
com.push_back(word);
}
for (int i = 0; i < (int)com.size(); i++) {
transform(com[i].begin(), com[i].end(), com[i].begin(), ::tolower);
if (com[i] == "show") {
display(vStu);
} else if (com[i] == "showid") {
displayID(vStu, "a11111111");
}
}
com.clear();
}
}
int main(int argc, char *argv[]) {
vector<Student> vStu;
int count = 0, x = 0;
if (argc != 2) {
cout << "Incorrectly called" << endl;
cout << " " << argv[0] << ' ' << "<filename>" << endl;
return 1;
}
addStudent(count, x, vStu, argv[1]);
mainMenu(vStu);
}
The only possibility I see is that there is some whitespace at the end of the string that gets passed into your function. Try trimming the end of the string's like this this thread suggests before comparing and see if they still don't compare correctly.

Different behavior with similar code

#include <vector>
#include <iostream>
using namespace std;
struct A
{
vector<int> v;
};
void f0(const A&& a0)
{
cout << &a0.v[0] << endl;
A a1{ move(a0.v) };
cout << &a1.v[0] << endl << endl;;
}
void f1()
{
A a0{ vector<int>(10) };
cout << &a0.v[0] << endl;
A a1{ move(a0.v) };
cout << &a1.v[0] << endl;
}
int main()
{
f0(A{ vector<int>(10) });
f1();
return 0;
}
I can't understand why in the first case addresses are different but in the second case addresses are same.

Resources