- Is the example wrong (or not accurate) on set type in declaration? - 1 Update
- C++ needs some help - 2 Updates
- Compilation error when using a std::vector iterator - 6 Updates
- "Bjarne Stroustrup announces C++ Core Guidelines" - 1 Update
- Help on relationship between two classes - 4 Updates
fl <rxjwg98@gmail.com>: Oct 06 02:59PM -0700 Hi, I am learning C++ through book 'C++ Primer'. When I read an example project, I find the set type used are different in declaration and definition, through it can build well through. Here is the declaration of class function 'eval': class AndQuery: public BinaryQuery { friend Query operator&(const Query&, const Query&); AndQuery(Query left, Query right): BinaryQuery(left, right, "&") { } // concrete class: AndQuery inherits display and defines remaining pure virtual std::set<line_no> eval(const TextQuery&) const; }; Here is the definition of function 'eval'. I see the return type is 'set<TextQuery::line_no>'. set<TextQuery::line_no> AndQuery::eval(const TextQuery& file) const { // virtual calls through the Query handle to get result sets for the operands set<line_no> left = lhs.eval(file), right = rhs.eval(file); set<line_no> ret_lines; // destination to hold results return ret_lines; } On class TextQuery, 'line_no' is defined as: class TextQuery { public: // typedef to make declarations easier typedef std::string::size_type str_size; typedef std::vector<std::string>::size_type line_no; It has a 'vector<std::string>', which is the same as 'std::set<line_no> '? Is the writing OK? Thanks, |
David Brown <david.brown@hesbynett.no>: Oct 06 08:44AM +0200 > Is there a growing sense that on line code generation > is to software what the wheel was to transportation? I have seen a few websites that have online code generation, and I guess for some purposes it might be useful. It would not surprise me if such systems became a little more popular, but they are very far from being revolutionary or even being particularly important outside niche areas. |
Christopher Pisz <nospam@notanaddress.com>: Oct 06 01:11PM -0500 > Is there a growing sense that on line code generation > is to software what the wheel was to transportation? No. Code generation is the devil. -- I have chosen to troll filter/ignore all subthreads containing the words: "Rick C. Hodgins", "Flibble", and "Islam" So, I won't be able to see or respond to any such messages --- |
Mark <i@dontgetlotsofspamanymore.net>: Oct 06 11:04AM +0100 I am trying to build some legacy C++ code. Much of the code uses the std::vector class and fails to compile. I have created a simple example which also gives the same error: ------------------------------------------------- #include <vector> using std::vector; class TestMessage { protected: char dummy[41]; }; class TestLink { public: typedef vector<TestMessage*> TestMsgVector; typedef TestMsgVector::iterator TestVectorIter; }; void doIt(const TestLink::TestMsgVector* pVector) { for (TestLink::TestVectorIter iter = pVector->begin(); // Compiler error here! iter != pVector->end(); ++iter) {} } int main() { TestLink::TestMsgVector vector; doIt(&vector); } ------------------------------------------------- Error message: test.cpp: In function void doIt(const TestLink::TestMsgVector*): test.cpp:20: error: conversion from __gnu_cxx::__normal_iterator<TestMessage* const*, std::vector<TestMessage*, std::allocator<TestMessage*> > > to non-scalar type TestLink::TestVectorIter requested What's wrong with this? And how to fix it? |
touc <ng@thebainbridges.me>: Oct 06 12:05PM +0100 On 06/10/15 11:04, Mark wrote: > { > ... > What's wrong with this? And how to fix it? It looks like a const mismatch, perhaps your iterator should be: typedef TestMsgVector::const_iterator TestVectorIter; |
guinness.tony@gmail.com: Oct 06 04:06AM -0700 On Tuesday, 6 October 2015 11:05:17 UTC+1, Mark wrote: > std::vector<TestMessage*, std::allocator<TestMessage*> > > to > non-scalar type TestLink::TestVectorIter requested > What's wrong with this? And how to fix it? pVector is a pointer to const object. The only member functions that can be called on such an object are the const-qualified ones. vector<> defines two overloads of member function begin() (and end()): - A non-qualified one that returns a vector<>::iterator; - A const-qualified one that returns a vector<>::const_iterator. Your code calls the second one (since *pVector is const). You cannot directly assign a const_iterator to an iterator. If the code in the loop will not modify any elements in the vector, change the second typedef in TestLink to name the TestMessageVector's const_iterator type, not iterator. If that code needs to actually modify elements in the vector, drop the 'const' from the parameter declaration of pVector. |
"Öö Tiib" <ootiib@hot.ee>: Oct 06 04:08AM -0700 On Tuesday, 6 October 2015 13:05:17 UTC+3, Mark wrote: > I am trying to build some legacy C++ code. Bjarne added 'const' to C++ 1981, it was initially called 'readonly'. Looks like legacy code from some alternative universe. > public: > typedef vector<TestMessage*> TestMsgVector; > typedef TestMsgVector::iterator TestVectorIter; That is 'iterator'. > }; > void doIt(const TestLink::TestMsgVector* pVector) That 'const TestLink::TestMsgVector*' causes that only 'const' members are callable. > { > for (TestLink::TestVectorIter iter = pVector->begin(); // Compiler > error here! That 'iter' is 'iterator', 'begin() const' returns 'const_iterator' and there are no conversions from 'const_iterator' to 'iterator'. > std::vector<TestMessage*, std::allocator<TestMessage*> > > to > non-scalar type TestLink::TestVectorIter requested > What's wrong with this? And how to fix it? Compiler wrote same thing what I wrote above but unfortunately the implementation details of standard library somewhat hide it in error message. To fix it you must be clear if you need 'const_iterator' or 'iterator'. The 'iterator' does convert to 'const_iterator' but not other way around. |
Mark <i@dontgetlotsofspamanymore.net>: Oct 06 01:01PM +0100 > > What's wrong with this? And how to fix it? >It looks like a const mismatch, perhaps your iterator should be: > typedef TestMsgVector::const_iterator TestVectorIter; Great :-) That's it. Thanks. |
Jorgen Grahn <grahn+nntp@snipabacken.se>: Oct 06 04:27PM On Tue, 2015-10-06, Mark wrote: >>It looks like a const mismatch, perhaps your iterator should be: >> typedef TestMsgVector::const_iterator TestVectorIter; > Great :-) That's it. Thanks. I wonder why it ever compiled -- if it did. Your use of the word "legacy" above sounds to me as a hint that it once did ... but I cannot think of a way that a standard library or compiler would allow it. /Jorgen -- // Jorgen Grahn <grahn@ Oo o. . . \X/ snipabacken.se> O o . |
legalize+jeeves@mail.xmission.com (Richard): Oct 06 03:07PM [Please do not mail me a copy of your followup] Vir Campestris <vir.campestris@invalid.invalid> spake the secret code >are interested in the interface. Which is the public stuff - so it comes >first. >The data is an implementation detail, and I'm happy to hide it. Bingo. If you need to understand the private members of a class in order to understand how to use it's public interface, then it is very likely that the class is poorly designed and doesn't have an intention revealing set of public methods. Having to study the implementation of a function or class in order to understand how to use it properly is a design smell. It means that the interface itself doesn't reveal enough about the semantics of the function or class for you to understand how to use it properly. The standard library does pretty well in this regard; so far I have never needed to reverse engineer anything in the standard library or inspect any private data members in order to know what these functions or classes do and how they are to be used. This is a good thing too, because for some reason people who write standard library implementations seem to enjoy the most cryptic of coding styles -- and we're not just talking about how the identifiers begin with _. -- "The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline> The Computer Graphics Museum <http://computergraphicsmuseum.org> The Terminals Wiki <http://terminals.classiccmp.org> Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com> |
fl <rxjwg98@gmail.com>: Oct 06 06:33AM -0700 Hi, I read a C++ project and cannot see why one class can use another class's member function. Here is the problem (I don't know why (*next_item) can call function book()): void Basket::display(ostream &os) const { os << "Basket size: " << items.size() << endl; // print each distinct isbn in the Basket along with // count of how many copies are ordered and what their price will be // upper_bound returns an iterator to the next item in the set for (const_iter next_item = items.begin(); next_item != items.end(); next_item = items.upper_bound(*next_item)) { // we know there's at least one element with this key in the Basket os << (*next_item)->book() << " occurs " << items.count(*next_item) << " times" << " for a price of " << (*next_item)->net_price(items.count(*next_item)) << endl; } } There are three classes are involved: Basket, Sales_item and Item_base. I first think Sales_item may access book(), but I don't see the definition. Here are they: class Item_base { friend std::istream& operator>>(std::istream&, Item_base&); friend std::ostream& operator<<(std::ostream&, const Item_base&); public: virtual Item_base* clone() const { return new Item_base(*this); } public: Item_base(const std::string &book = "", double sales_price = 0.0): isbn(book), price(sales_price) { } std::string book() const { return isbn; } // returns total sales price for a specified number of items // derived classes will override and apply different discount algorithms virtual double net_price(std::size_t n) const { return n * price; } // no work, but virtual destructor needed // if base pointer that points to a derived object is ever deleted virtual ~Item_base() { } private: std::string isbn; // identifier for the item protected: double price; // normal, undiscounted price }; class Sales_item { friend class Basket; public: // default constructor: unbound handle Sales_item(): p(0), use(new std::size_t(1)) { } // attaches a handle to a copy of the Item_base object Sales_item(const Item_base&); // copy control members to manage the use count and pointers Sales_item(const Sales_item &i): p(i.p), use(i.use) { ++*use; } ~Sales_item() { decr_use(); } Sales_item& operator=(const Sales_item&); // member access operators const Item_base *operator->() const { if (p) return p; else throw std::logic_error("unbound Sales_item"); } const Item_base &operator*() const { if (p) return *p; else throw std::logic_error("unbound Sales_item"); } private: Item_base *p; // pointer to shared item std::size_t *use; // pointer to shared use count // called by both destructor and assignment operator to free pointers void decr_use() { if (--*use == 0) { delete p; delete use; } } }; // holds items being purchased class Basket { // type of the comparison function used to order the multiset typedef bool (*Comp)(const Sales_item&, const Sales_item&); public: // make it easier to type the type of our set typedef std::multiset<Sales_item, Comp> set_type; // typedefs modeled after corresponding container types typedef set_type::size_type size_type; typedef set_type::const_iterator const_iter; void display(std::ostream&) const; // workaround MS compiler bug: must explicitly pass function address Basket(): items(&compare) { } // initialze the comparator void add_item(const Sales_item &item) { items.insert(item); } size_type size(const Sales_item &i) const { return items.count(i); } double total() const; // sum of net prices for all items in the basket private: std::multiset<Sales_item, Comp> items; }; book() is Item_base' member function. Why can (*next_item)->book() be used? Thanks, |
fl <rxjwg98@gmail.com>: Oct 06 06:40AM -0700 On Tuesday, October 6, 2015 at 9:33:29 AM UTC-4, fl wrote: > }; > book() is Item_base' member function. Why can (*next_item)->book() be used? > Thanks, Sales_item has a pointer to Item_base, but the iterator to std::multiset<Sales_item, Comp> point to Sales_item, not Sales_item's private member: Item_base *p; // pointer to shared item Can you help me? Thanks, |
"Öö Tiib" <ootiib@hot.ee>: Oct 06 06:49AM -0700 On Tuesday, 6 October 2015 16:33:29 UTC+3, fl wrote: > std::multiset<Sales_item, Comp> items; > }; > book() is Item_base' member function. Why can (*next_item)->book() be used? Because 'Sales_item' has overloaded the member access operator and there is "drill down behavior" so you don't have to write '(*next_item)->->book()' or something like that. |
Ben Bacarisse <ben.usenet@bsb.me.uk>: Oct 06 03:23PM +0100 fl <rxjwg98@gmail.com> writes: Replying to your own followup so everything is double quoted. > On Tuesday, October 6, 2015 at 9:33:29 AM UTC-4, fl wrote: <snip> >> void Basket::display(ostream &os) const >> { <snip> >> { >> // we know there's at least one element with this key in the Basket >> os << (*next_item)->book() << " occurs " items is a multiset of Sales_item, so *next_item is if type const Sales_item. <snip> >> << endl; >> } >> } <snip> >> class Item_base { <snip> >> std::string book() const { return isbn; } <snip> >> class Sales_item { >> friend class Basket; >> public: <snip> >> const Item_base *operator->() const { if (p) return p; >> else throw std::logic_error("unbound Sales_item"); } This operator is the key. <snip> >> }; <snip> >> // holds items being purchased >> class Basket { <snip> >> }; >> book() is Item_base' member function. Why can (*next_item)->book() be >> used? So, *next_item is if type const Sales_item but Sales_item defines operator-> so an expression of the form x->m is interpreted as (x.operator->())->m for a class object x. I.e. (*next_item)->book() means ((*next_item).operator->())->book(); Do you see it now? <snip> -- Ben. |
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment