PHWinfo banniere

Titres
PORTAIL ANNUAIRE ARTICLES COMPARATEUR HÉBERGEURS DEVIS FORUMS RÉDUCTEUR D'URL
Précédent   PHWinfo > Autres forums > Forum Programmation & Conception > comp.lang.cplus > Constructor syntax woes.
S'inscrire FAQ Membres Recherche Messages du jour Marquer les forums comme lus
Constructor syntax woes.

Réponse
 
LinkBack Outils de la discussion
Vieux 16/07/2008, 01h21   #1
willo@cynd.net
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Constructor syntax woes.

Greetings all,

I have run into a small problem with my understanding of some C++
language syntax, and seek some clarification.

Below is a condensed version of some code I'm having difficulty with:

================================================== =============

#include <cstddef> // size_t
#include <functional> // binary_function

// the input parameter type to a class constructor.
template< typename T >
struct ABinaryFunction : public std::binary_function< T, size_t,
double >
{
typename ABinaryFunction::result_type
operator()( typename ABinaryFunction< T >::first_argument_type lhs,
typename ABinaryFunction< T >::second_argument_type
rhs )
{
return ABinaryFunction< T >::result_type();
}
};

template< typename T >
class AClass
{
public:

// constructor takes one specialized binary_function type parameter.
AClass( std::binary_function< T, size_t, double > function )
{
}

// arbitrary method to test instantiation.
bool True()
{
return true;
}
};

int main()
{
// this won't create a class of type "AClass".
AClass< int > instance_a( ABinaryFunction< int >() );
// this will not compile.
bool bool_a = instance_a.True();

// this will create a class of type "AClass", along with an unwanted
binary_function_b.
ABinaryFunction< int > binary_function_b;
AClass< int > instance_b( binary_function_b );
// this will compile.
bool bool_b = instance_b.True();

return 0;
}

================================================== =============

I'm using gcc-4.3, and get the following compile-error:

test.cpp:37: error: request for member ‘True’ in ‘instance_a’, which
is of non-class type ‘AClass<int> ()(ABinaryFunction<int> (*)())'

I'm not very adept at deciphering uncommon C++ syntax, but my best
guess is that line 37 is interpreted as a definition or declaration of
the parenthesis operator, which takes a pointer to ABinaryFunction's
parenthesis operator, and returns AClass. This is not what I expected
or intended at all.

What I wish to know is: why does the first stanza in main not
compile? To me, it is exactly the same as the second stanza; what am
I missing?

The second stanza works, so I can get by. However, using an anonymous
temporary ABinaryFunction object inline, as I intended stanza one to
be, is cleaner / more intuitive. Additionally, I'd like to know what
the syntax should be for what I intended, ( assuming it's possible. )

Thanks for your consideration,

-- Charles Wilcox
  Réponse avec citation
Vieux 16/07/2008, 02h24   #2
Alf P. Steinbach
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Constructor syntax woes.

* willo@cynd.net:
>
> Below is a condensed version of some code I'm having difficulty with:
>
> ================================================== =============
>
> #include <cstddef> // size_t


Well, with the current standard formally this only gives you std::size_t, but
all or nearly all compilers also place it in the global namespace. With C++0x
it's allowed to also give you size_t in global namespace. Because of that it's
now, IMHO, misleading to use the <c...> headers; just use <stddef.h>.


> #include <functional> // binary_function
>
> // the input parameter type to a class constructor.
> template< typename T >
> struct ABinaryFunction : public std::binary_function< T, size_t,
> double >
> {
> typename ABinaryFunction::result_type
> operator()( typename ABinaryFunction< T >::first_argument_type lhs,
> typename ABinaryFunction< T >::second_argument_type
> rhs )
> {
> return ABinaryFunction< T >::result_type();
> }
> };


OK, except you'll probably want to add a 'const' for the operator() (presumably
it's not changing the functor object, but just computing something).


> template< typename T >
> class AClass
> {
> public:
>
> // constructor takes one specialized binary_function type parameter.
> AClass( std::binary_function< T, size_t, double > function )
> {
> }


If you want to somehow retain the functor object then you need to use some other
kind of argument, possibly a templated constructor. As it is your actual
argument will be sliced to std::binary_function. Not much you can do with a pure
std::binary_function!

>
> // arbitrary method to test instantiation.
> bool True()
> {
> return true;
> }
> };
>
> int main()
> {
> // this won't create a class of type "AClass".
> AClass< int > instance_a( ABinaryFunction< int >() );


This is an example of what's been called "the most vexing parse" in C++. The
rule is that if the compiler can treat a declaration as a function declaration,
it will. And here it can, so it does.

You can fiddle with extra parentheses and the like, to convince the compiler
that that argument can't possibly be a type, but that yields unclear code.

So instead just do

ABinaryFunction<int> foo;
AClass<int> instance_a( foo );

Or you can introduce a factory function for your binary functors,

template< typename T >
ABinaryFunction<T> aBinaryFunction() { return ABinaryFunction<T>(); }

and then in main you can declare

AClass<int> instance_a( aBinaryFunction<int>() );

Anyway, as noted earlier, this actual argument will be sliced.


> // this will not compile.
> bool bool_a = instance_a.True();
>
> // this will create a class of type "AClass", along with an unwanted
> binary_function_b.
> ABinaryFunction< int > binary_function_b;
> AClass< int > instance_b( binary_function_b );
> // this will compile.
> bool bool_b = instance_b.True();


Yes, that's OK.


> return 0;
> }



Cheers, & hth.,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
  Réponse avec citation
Vieux 16/07/2008, 02h29   #3
Sam
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Constructor syntax woes.

willo@cynd.net writes:

> [ snippety ]
>
> I'm not very adept at deciphering uncommon C++ syntax, but my best
> guess is that line 37 is interpreted as a definition or declaration of
> the parenthesis operator, which takes a pointer to ABinaryFunction's
> parenthesis operator, and returns AClass. This is not what I expected
> or intended at all.


No, it appears to be parsed as a function prototype, that's what appears to
be happening. Consider the following statement:

int foo (char () );

This gets parsed as a prototype of a function that returns an int, and takes
a parameter that's a pointer to a function that returns a char, and takes
no parameters.

Your declaration is:

AClass< int > instance_a( ABinaryFunction<int>() );

This apparently gets parsed a function prototype: a prototype for a function
that returns an AClass<int>, and that takes an argument of a pointer to a
function that returns an ABinaryFunction<int>, and takes no arguments.

When templates are involved, weird parsing anomalies like this are quite
common. I'm sure there's some obscure clause in the C++ standard that
explains why this gets parsed this way, but that's an academic excersize. I
note that if you change this to:

AClass< int > instance_a( (ABinaryFunction<int>()) );

This apparently does what you want: invoke the default constructor for
ABinaryFunction<int>, and pass the result as the argument to AClass<int>'s
constructor.

Heh, this is a nice one.



-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEABECAAYFAkh9QQQACgkQx9p3GYHlUOKAngCcDHSHPWH8ZJ XoG/hkolJnhxRi
U6cAn0YdD8w/dcTuyaAIj0CL6NjR4ips
=NWMO
-----END PGP SIGNATURE-----

  Réponse avec citation
Vieux 16/07/2008, 04h09   #4
willo@cynd.net
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Constructor syntax woes.

On Jul 15, 7:21pm, wi...@cynd.net wrote:
> Greetings all,
>
> I have run into a small problem with my understanding of some C++
> language syntax, and seek some clarification.
>
> Below is a condensed version of some code I'm having difficulty with:
>
> ================================================== =============
>
> #include <cstddef> // size_t
> #include <functional> // binary_function
>
> // the input parameter type to a class constructor.
> template< typename T >
> struct ABinaryFunction : public std::binary_function< T, size_t,
> double >
> {
> typename ABinaryFunction::result_type
> operator()( typename ABinaryFunction< T >::first_argument_type lhs,
> typename ABinaryFunction< T >::second_argument_type
> rhs )
> {
> return ABinaryFunction< T >::result_type();
> }
>
> };
>
> template< typename T >
> class AClass
> {
> public:
>
> // constructor takes one specialized binary_function type parameter.
> AClass( std::binary_function< T, size_t, double > function )
> {
> }
>
> // arbitrary method to test instantiation.
> bool True()
> {
> return true;
> }
>
> };
>
> int main()
> {
> // this won't create a class of type "AClass".
> AClass< int > instance_a( ABinaryFunction< int >() );
> // this will not compile.
> bool bool_a = instance_a.True();
>
> // this will create a class of type "AClass", along with an unwanted
> binary_function_b.
> ABinaryFunction< int > binary_function_b;
> AClass< int > instance_b( binary_function_b );
> // this will compile.
> bool bool_b = instance_b.True();
>
> return 0;
>
> }
>
> ================================================== =============
>
> I'm using gcc-4.3, and get the following compile-error:
>
> test.cpp:37: error: request for member ‘True’ in ‘instance_a’, which
> is of non-class type ‘AClass<int> ()(ABinaryFunction<int> (*)())'
>
> I'm not very adept at deciphering uncommon C++ syntax, but my best
> guess is that line 37 is interpreted as a definition or declaration of
> the parenthesis operator, which takes a pointer to ABinaryFunction's
> parenthesis operator, and returns AClass. This is not what I expected
> or intended at all.
>
> What I wish to know is: why does the first stanza in main not
> compile? To me, it is exactly the same as the second stanza; what am
> I missing?
>
> The second stanza works, so I can get by. However, using an anonymous
> temporary ABinaryFunction object inline, as I intended stanza one to
> be, is cleaner / more intuitive. Additionally, I'd like to know what
> the syntax should be for what I intended, ( assuming it's possible. )
>
> Thanks for your consideration,
>
> -- Charles Wilcox


This evening I realized I could explicitly break the line into a
declaration and "constructor by assignment" as follows:

AClass< int > instance_a = AClass< int >( ABinaryFunction< int
>() );


I know the "constructor by assignment" is a bit confusing to some, but
I know it's actually using the explicit constructor only, as I put
"operator=" into a "private" section.

I like it a bit more than stanza two; I'll use this potentially.
  Réponse avec citation
Vieux 16/07/2008, 04h23   #5
willo@cynd.net
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Constructor syntax woes.

On Jul 15, 8:24pm, "Alf P. Steinbach" <al...@start.no> wrote:
> * wi...@cynd.net:
>
>
>
> > Below is a condensed version of some code I'm having difficulty with:

>
> > ================================================== =============

>
> > #include <cstddef> // size_t

>
> Well, with the current standard formally this only gives you std::size_t,but
> all or nearly all compilers also place it in the global namespace. With C++0x
> it's allowed to also give you size_t in global namespace. Because of thatit's
> now, IMHO, misleading to use the <c...> headers; just use <stddef.h>.
>
> > #include <functional> // binary_function

>
> > // the input parameter type to a class constructor.
> > template< typename T >
> > struct ABinaryFunction : public std::binary_function< T, size_t,
> > double >
> > {
> > typename ABinaryFunction::result_type
> > operator()( typename ABinaryFunction< T >::first_argument_type lhs,
> > typename ABinaryFunction< T >::second_argument_type
> > rhs )
> > {
> > return ABinaryFunction< T >::result_type();
> > }
> > };

>
> OK, except you'll probably want to add a 'const' for the operator() (presumably
> it's not changing the functor object, but just computing something).
>
> > template< typename T >
> > class AClass
> > {
> > public:

>
> > // constructor takes one specialized binary_function type parameter..
> > AClass( std::binary_function< T, size_t, double > function )
> > {
> > }

>
> If you want to somehow retain the functor object then you need to use some other
> kind of argument, possibly a templated constructor. As it is your actual
> argument will be sliced to std::binary_function. Not much you can do witha pure
> std::binary_function!
>
>
>
> > // arbitrary method to test instantiation.
> > bool True()
> > {
> > return true;
> > }
> > };

>
> > int main()
> > {
> > // this won't create a class of type "AClass".
> > AClass< int > instance_a( ABinaryFunction< int >() );

>
> This is an example of what's been called "the most vexing parse" in C++. The
> rule is that if the compiler can treat a declaration as a function declaration,
> it will. And here it can, so it does.
>
> You can fiddle with extra parentheses and the like, to convince the compiler
> that that argument can't possibly be a type, but that yields unclear code..
>
> So instead just do
>
> ABinaryFunction<int> foo;
> AClass<int> instance_a( foo );
>
> Or you can introduce a factory function for your binary functors,
>
> template< typename T >
> ABinaryFunction<T> aBinaryFunction() { return ABinaryFunction<T>(); }
>
> and then in main you can declare
>
> AClass<int> instance_a( aBinaryFunction<int>() );
>
> Anyway, as noted earlier, this actual argument will be sliced.
>
> > // this will not compile.
> > bool bool_a = instance_a.True();

>
> > // this will create a class of type "AClass", along with an unwanted
> > binary_function_b.
> > ABinaryFunction< int > binary_function_b;
> > AClass< int > instance_b( binary_function_b );
> > // this will compile.
> > bool bool_b = instance_b.True();

>
> Yes, that's OK.
>
> > return 0;
> > }

>
> Cheers, & hth.,
>
> - Alf
>
> --
> A: Because it messes up the order in which people normally read text.
> Q: Why is it such a bad thing?
> A: Top-posting.
> Q: What is the most annoying thing on usenet and in e-mail?


Alf,

Thanks for the pointers and suggestions. I know the code I provided
wasn't terribly functional; I just stripped out everything I could
think of and still demonstrate the problem. You're right on the
ABinaryFunction inheritance bit-slicing; however most derived versions
of std::binary_function() are to re-define 'operator()', so it's
okay. If I had state, I'd virtualize the destructor.

As you mentioned, and Sam showed, the double-parens trick also works.
Kinda subtle. Not sure if I like that over my explicit declaration
and "construction by assignment" version more. But the point is, now
I have some options; I'll have to comment the code accordingly for
either fix.

-- Charles Wilcox
  Réponse avec citation
Vieux 16/07/2008, 04h28   #6
willo@cynd.net
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Constructor syntax woes.

On Jul 15, 8:29pm, Sam <s...@email-scan.com> wrote:
> wi...@cynd.net writes:
> > [ snippety ]

>
> > I'm not very adept at deciphering uncommon C++ syntax, but my best
> > guess is that line 37 is interpreted as a definition or declaration of
> > the parenthesis operator, which takes a pointer to ABinaryFunction's
> > parenthesis operator, and returns AClass. This is not what I expected
> > or intended at all.

>
> No, it appears to be parsed as a function prototype, that's what appears to
> be happening. Consider the following statement:
>
> int foo (char () );
>
> This gets parsed as a prototype of a function that returns an int, and takes
> a parameter that's a pointer to a function that returns a char, and takes
> no parameters.
>
> Your declaration is:
>
> AClass< int > instance_a( ABinaryFunction<int>() );
>
> This apparently gets parsed a function prototype: a prototype for a function
> that returns an AClass<int>, and that takes an argument of a pointer to a
> function that returns an ABinaryFunction<int>, and takes no arguments.
>
> When templates are involved, weird parsing anomalies like this are quite
> common. I'm sure there's some obscure clause in the C++ standard that
> explains why this gets parsed this way, but that's an academic excersize.I
> note that if you change this to:
>
> AClass< int > instance_a( (ABinaryFunction<int>()) );
>
> This apparently does what you want: invoke the default constructor for
> ABinaryFunction<int>, and pass the result as the argument to AClass<int>'s
> constructor.
>
> Heh, this is a nice one.
>
> application_pgp-signature_part
> 1KDownload


Sam,

Thanks for the input. I see your point, that it's declaring a
function prototype.

The double-parens trick is very cute, although it's not very clear /
why/ it works. It's a bit subtle... I think I'd almost prefer
something more explicit. As I just previously posted, I was able to
make the line compile by breaking it out into a variable declaration,
and a "constructor by assignment". Of course, that could confuse
people into thinking a real assignment is happening.

Ahh well, the fun of C++ parsing legacy.

-- Charles Wilcox
  Réponse avec citation
Vieux 16/07/2008, 04h30   #7
Alf P. Steinbach
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Constructor syntax woes.

* willo@cynd.net:
>
> Thanks for the pointers and suggestions. I know the code I provided
> wasn't terribly functional; I just stripped out everything I could
> think of and still demonstrate the problem. You're right on the
> ABinaryFunction inheritance bit-slicing; however most derived versions
> of std::binary_function() are to re-define 'operator()', so it's
> okay. If I had state, I'd virtualize the destructor.


It's not just a matter of state. It's a matter of invoking the right operator().
Happily std::binary_function doesn't define an operator(), so if you have
misunderstood this you'll discover the problem once you try to use it... ;-)


Cheers, & hth.,

- Alf

PS: Please don't quote signatures or other extraneous material. DS.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
  Réponse avec citation
Réponse


Outils de la discussion

Règles de messages
Vous ne pouvez pas créer de nouvelles discussions
Vous ne pouvez pas envoyer des réponses
Vous ne pouvez pas envoyer des pièces jointes
Vous ne pouvez pas modifier vos messages

Les balises BB sont activées : oui
Les smileys sont activés : oui
La balise [IMG] est activée : oui
Le code HTML peut être employé : non
Trackbacks are oui
Pingbacks are oui
Refbacks are oui


Fuseau horaire GMT +1. Il est actuellement 16h50.


Édité par : vBulletin® version 3.7.3
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.2.0 RC5 Tous droits réservés.
Version française #16 par l'association vBulletin francophone
PHWinfo est un site Éducation Sans Frontières ©2000-2008
Ad Management by RedTyger
©Tous droits réservés par les parties respectives
Page generated in 0,24319 seconds with 15 queries