|
|
|
#1 |
|
Messages: n/a
Hébergeur: |
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 |
|
|
|
#2 |
|
Messages: n/a
Hébergeur: |
* 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? |
|
|
|
#3 |
|
Messages: n/a
Hébergeur: |
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----- |
|
|
|
#4 |
|
Messages: n/a
Hébergeur: |
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. |
|
|
|
#5 |
|
Messages: n/a
Hébergeur: |
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 |
|
|
|
#6 |
|
Messages: n/a
Hébergeur: |
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 |
|
|
|
#7 |
|
Messages: n/a
Hébergeur: |
* 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? |
|
![]() |
| Outils de la discussion | |
|
|