C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Query regd. validity of a C++ program

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language, library and standards
View previous topic :: View next topic  
Author Message
frame
Guest





PostPosted: Mon Sep 25, 2006 5:25 pm    Post subject: Query regd. validity of a C++ program Reply with quote



Hi,

The other day, I was experimenting with Predicates and STL and came
across a gotcha with the following program. The objective of the
program is to remove those strings, from a vector of strings, whose
size is of atleast a specified length (here 5) and contains atleast a
specified number of punctuation characters, excluding '@' (here 2).
There are 3 classes: Length and NumberOfSpecialChars in 'Parameters'
namespace (which are just wrappers around 'unsigned long') and
SpecialStringChecker in 'Processor' namespace. The problem, I am
facing, is the following program isn't getting complied under both
GNU's 'g++' and SUN Studio's 'CC'. Both are trying to convert
std::basic_string<...> to `Parameters::Length' (Don't know, why?) in
the remove_if(...) call. Interestingly, the program gets complied and
runs as expected if the commented lines are substituted for the
following uncommented parts. I am not sure, why are the compliers
reporting a problem with user-defined types (Length and
NumberOfSpecialChars), but not for a fundamental type (unsigned long)
or am I blowing this somewhere?

#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <string>
#include <iterator>
#include <ctype.h>

namespace Parameters{

class Length{
unsigned long length_;
public:
explicit Length(const unsigned long& length): length_(length) {}
operator unsigned long() const{
return length_;
}
};

class NumberOfSpecialChars{
unsigned long numberOfSpecialChars_;
public:
explicit NumberOfSpecialChars(const unsigned long&
numberOfSpecialChars):
numberOfSpecialChars_(numberOfSpecialChars) {}
operator unsigned long() const{
return numberOfSpecialChars_;
}
};

}

namespace Processor{

using namespace Parameters;
using namespace std;

class SpecialStringChecker{
Length length_;
NumberOfSpecialChars numberOfSpecialChars_;
public:
bool operator()(const string& s) const{
if(s.length() >= (unsigned long)(length_))
{
unsigned long matches = count_if(s.begin(), s.end(), *this);

if(matches >= (unsigned long)(numberOfSpecialChars_))
return true;
}
return false;
}
bool operator()(const char& c) const{
if(ispunct(c) && c !='@')
return true;
return false;
}
/*explicit SpecialStringChecker(const unsigned long& length,
const unsigned long& numberOfSpecialChars):
length_(length),
numberOfSpecialChars_(numberOfSpecialChars) {}*/
explicit SpecialStringChecker(const Length& length,
const NumberOfSpecialChars&
numberOfSpecialChars):
length_(length),
numberOfSpecialChars_(numberOfSpecialChars) {}
};

}

using namespace std;
using namespace Parameters;
using namespace Processor;

int main(int argc, char* argv[]){
vector<string> myStrVec;
myStrVec.push_back(string("%@text1&!#"));
myStrVec.push_back(string("text2"));
myStrVec.push_back(string("@text3"));
myStrVec.push_back(string("!#$%"));
unsigned long length=5, numberOfSpecialChars=2;
//SpecialStringChecker myStrChkr(length, numberOfSpecialChars);
SpecialStringChecker myStrChkr(Length(length),
NumberOfSpecialChars(numberOfSpecialChars));
vector<string>::iterator myStrVecItr;
myStrVecItr = remove_if(myStrVec.begin(), myStrVec.end(), myStrChkr);
myStrVec.erase(myStrVecItr, myStrVec.end());
copy(myStrVec.begin(), myStrVec.end(),
ostream_iterator<string>(cout,"\n"));
return 0;
}

//Thanks in advance to the takers!!

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Alberto Ganesh Barbati
Guest





PostPosted: Tue Sep 26, 2006 3:11 am    Post subject: Re: Query regd. validity of a C++ program Reply with quote



frame ha scritto:

Quote:
SpecialStringChecker myStrChkr(Length(length),
NumberOfSpecialChars(numberOfSpecialChars));

Another case of the C++ Most Vexing Parse! This is not a declaration of
an object of type SpecialStringChecker but rather the declaration of a
function that takes two parameters of type Length and
NumberOfSpecialChars respectively. So when you pass myStrChkr to the
algorithms, all they get is a pointer to a function expecting two
parameters but it's used with only one parameter (and of the wrong
kind). Thus the compiler rightly complains...

Ganesh

PS: if you want to know more, just google for "C++ most vexing parse".

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Earl Purple
Guest





PostPosted: Tue Sep 26, 2006 3:40 pm    Post subject: Re: Query regd. validity of a C++ program Reply with quote



Is that whole thing your own program or something you were given to
assess. Anyway you should point out in such a post where it is not
compiling.

frame wrote:
Quote:
SpecialStringChecker myStrChkr(Length(length), NumberOfSpecialChars(numberOfSpecialChars));

To me it is unambiguous that you are passing two temporaries into a
constructor. What else can Length(length) and
NumberOfSpecialChars(numberOfSpecialChars) be?

I am hoping, and given this is comp.std.c++ not
comp.lang.c++(.moderated), that this issue has been raised for the next
standard. Given the brackets following Length and NumberOfSpecialChars,
I don't see how this is a function declaration.

Anyway, the "workaround" if you really want temporaries is to create
functions to create them so (and you don't have to use these exact
names of course)

Length make_length( unsigned long u )
{
return Length( u );
}

NumberOfSpecialChars make_numberOfSpecialChars( unsigned long u )
{
return NumberOfSpecialChars( u );
}

========

then you can happily replace your above line with:

SpecialStringChecker myStrChkr(make_length(length),
make_numberOfSpecialChars(numberOfSpecialChars);

and your compiler will stop complaining. To do this the classes you
create will have to have an accessible copy-constructor even RVO will
probably mean that in reality they won't be copied.

Some compilers will also allow an extra set of brackets. gcc doesn't
though (at least my version doesn't) and that's usually very compliant.

If your class takes the parameters by const-reference and the
parameters you are passing do not have an accessible copy constructor
then you are stuck with having to create them first then pass them in
as non-temporaries.

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Alberto Ganesh Barbati
Guest





PostPosted: Tue Sep 26, 2006 10:52 pm    Post subject: Re: Query regd. validity of a C++ program Reply with quote

Earl Purple ha scritto:
Quote:
frame wrote:
SpecialStringChecker myStrChkr(Length(length), NumberOfSpecialChars(numberOfSpecialChars));

To me it is unambiguous that you are passing two temporaries into a
constructor.

Also to me and to the OP, but not to the compiler. But from the rest of
the post it seems that you already knew that ;-)

Quote:
What else can Length(length) and
NumberOfSpecialChars(numberOfSpecialChars) be?

Declaration of formal parameters of type Length and
NumberOfSpecialChars, with names length and numberOfSpecialChars. The
extra parentheses are ignored by the parse (but you already knew that
too, I believe). In order to fix that you would need to add a special
disambiguation case and that means messing with the already very complex
declarator syntax. It's probably not impossible, but looks quite hard to
me. Anyway, if you can come up with a wording for that, I guess
everybody is ready to listen.

Quote:
I am hoping, and given this is comp.std.c++ not
comp.lang.c++(.moderated), that this issue has been raised for the next
standard. Given the brackets following Length and NumberOfSpecialChars,
I don't see how this is a function declaration.

Anyway, the "workaround" if you really want temporaries is to create
functions to create them so (and you don't have to use these exact
names of course)

snip

SpecialStringChecker myStrChkr(make_length(length),
make_numberOfSpecialChars(numberOfSpecialChars);

There are at least two much easier workarounds. One is to put an extra
pair of parenthesis to the first argument like this:

SpecialStringChecker myStrChkr((Length(length)),
NumberOfSpecialChars(numberOfSpecialChars));

the other is to replace function-style casts with C-style casts:

SpecialStringChecker myStrChkr((Length)length,
(NumberOfSpecialChars)numberOfSpecialChars);

these will stop the parser to think Length is a type.

Quote:
Some compilers will also allow an extra set of brackets. gcc doesn't
though (at least my version doesn't) and that's usually very compliant.

It's very strange that gcc doesn't accept that. It's not a
compiler-dependent hack, it's a perfectly valid syntax, so gcc would be
bugged if it doesn't accept it. Perhaps you put by mistake the
parenthesis around both arguments?

Ganesh

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
kanze
Guest





PostPosted: Wed Sep 27, 2006 2:50 pm    Post subject: Re: Query regd. validity of a C++ program Reply with quote

Earl Purple wrote:
Quote:
Is that whole thing your own program or something you were
given to assess. Anyway you should point out in such a post
where it is not compiling.

frame wrote:
SpecialStringChecker myStrChkr(Length(length), NumberOfSpecialChars(numberOfSpecialChars));

To me it is unambiguous that you are passing two temporaries
into a constructor. What else can Length(length) and
NumberOfSpecialChars(numberOfSpecialChars) be?

Parameter declarations. Obviously:-).

Quote:
I am hoping, and given this is comp.std.c++ not
comp.lang.c++(.moderated), that this issue has been raised for
the next standard.

Raising an issue isn't the same as solving the problem. You
don't want to break existing code, for example, so some obvious
solutions are out of the window.

Quote:
Given the brackets following Length and NumberOfSpecialChars,
I don't see how this is a function declaration.

SpecialStringChecker myStrChkr( Length (&p)[ 10 ] ) ;

There are bracket after Length there. And yet, it can't be
anything but a function declaration.

The issue is more complex than you seem to think.

Quote:
Anyway, the "workaround" if you really want temporaries is to
create functions to create them so (and you don't have to use
these exact names of course)

Length make_length( unsigned long u )
{
return Length( u );
}

NumberOfSpecialChars make_numberOfSpecialChars( unsigned long u )
{
return NumberOfSpecialChars( u );
}

Even simpler: you put the initialization expression in
parentheses. A declaration cannot be entirely in parentheses.

Quote:
========

then you can happily replace your above line with:

SpecialStringChecker myStrChkr(make_length(length),
make_numberOfSpecialChars(numberOfSpecialChars);

and your compiler will stop complaining. To do this the
classes you create will have to have an accessible
copy-constructor even RVO will probably mean that in reality
they won't be copied.

If he's passing them by value, he needs the copy-constructor for
that as well, so it's no problem. Ditto if he's passing by
const reference. And if he's passing by non-const reference, he
can't bind a temporary anyway.

Quote:
Some compilers will also allow an extra set of brackets. gcc
doesn't though (at least my version doesn't) and that's
usually very compliant.

Are you sure? I have no problem with extra parentheses with my
version of g++ (4.1.0).

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
kanze
Guest





PostPosted: Wed Sep 27, 2006 2:51 pm    Post subject: Re: Query regd. validity of a C++ program Reply with quote

Alberto Ganesh Barbati wrote:
Quote:
Earl Purple ha scritto:
snip

SpecialStringChecker myStrChkr(make_length(length),
make_numberOfSpecialChars(numberOfSpecialChars);

There are at least two much easier workarounds. One is to put
an extra pair of parenthesis to the first argument like this:

SpecialStringChecker myStrChkr((Length(length)),
NumberOfSpecialChars(numberOfSpecialChars));

Around either or both will work according to the standard. In
the past, g++ committed one way or the other after the first
parentheses, which meant just putting them around the last
didn't work. This is a bug---I don't know if it has been
fixed, since I just regularly put them around any expression
which starts with the name of a type.

Quote:
the other is to replace function-style casts with C-style casts:

SpecialStringChecker myStrChkr((Length)length,
(NumberOfSpecialChars)numberOfSpecialChars);

these will stop the parser to think Length is a type.

You can also use static_cast.

Changing the type of cast only works for constructors with a
single parameter, however. It doesn't solve the problem for:

C a( C() ) ;

(which, as it stands declares an external function a returning a
C and taking a pointer to a function returning a C and taking no
parameters as paramter.

Quote:
Some compilers will also allow an extra set of brackets. gcc
doesn't though (at least my version doesn't) and that's
usually very compliant.

It's very strange that gcc doesn't accept that.

4.1.0 does. It's the solution I normally use now, and I can't
recall having had problems with it in the past.

Quote:
It's not a compiler-dependent hack, it's a perfectly valid
syntax, so gcc would be bugged if it doesn't accept it.
Perhaps you put by mistake the parenthesis around both
arguments?

Which will also compile, if there is also a constructor which
takes a single parameter of the type of the second expression.
Of course, if what you want is the constructor with two
parameters, it's not what you'll get.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language, library and standards All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.