Topic: Query regd. validity of a C++ program
Author: "frame" <v.srikar@gmail.com>
Date: Mon, 25 Sep 2006 11:25:08 CST Raw View
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 ]
Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Mon, 25 Sep 2006 22:11:07 GMT Raw View
frame ha scritto:
> 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 ]
Author: "Earl Purple" <earlpurple@gmail.com>
Date: Tue, 26 Sep 2006 09:40:07 CST Raw View
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?
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 ]
Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Tue, 26 Sep 2006 17:52:45 GMT Raw View
Earl Purple ha scritto:
> 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 ;-)
> 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.
> 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.
> 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 ]
Author: "kanze" <kanze@gabi-soft.fr>
Date: Wed, 27 Sep 2006 08:50:27 CST Raw View
Earl Purple wrote:
> 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:-).
> 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.
> 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.
> 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.
> ========
>
> 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.
> 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 ]
Author: "kanze" <kanze@gabi-soft.fr>
Date: Wed, 27 Sep 2006 08:51:06 CST Raw View
Alberto Ganesh Barbati wrote:
> 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.
> 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.
> > 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.
> 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 ]