Tuesday, October 6, 2015

Digest for comp.lang.c++@googlegroups.com - 14 updates in 5 topics

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: