Constructor syntax woes.

W

willo

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
 
W

willo

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 said:

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.
 
W

willo

* (e-mail address removed):




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



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).



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!





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.



Yes, that's OK.


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
 
W

willo

[ 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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top