Is it legal code?

P

Paul

itaj sherman said:
Actually even better:

struct A
{
public: void bar()
{
}
};

void foo( A& )
{
}

// foo and bar don't exist here.

typedef void (*FuncPtr)( A& );
typedef void (A::*MemberFuncPtr)();

int main()
{
//they don't exist here either.
FuncPtr x = &foo;
MemberFuncPtr y = &A::bar;
//OMG, they don't yet exist even here.
A a;
// aah there you go, an object exists, and now the functions also
exist.
foo( a );
a.bar();
}
That's more or less correct I would say.
I'm not sure if it's 100% correct to say the function does not exist but I
think it is certainly correct to say that no member of 'a' exists until 'a'
itself exists.
 
P

Paul

You must've forgot we are talking about *member functions*.

Why?
Why you only stick to nonstatic member function?
Why can't you deal with this issue generally about all functions?
IMO, if you do that it will clear a lot of the confusion.

.................................................................................

You are probably correct, I find it difficult to think about member
functions without objects.
 
I

itaj sherman

That's more or less correct I would say.
I'm not sure if it's 100% correct to say the function does not exist
but I
think it is certainly correct to say that no member of 'a' exists until 'a'
itself exists.

It depends on what exactly one means by function "exists".
I only ever used "declared" and "defined" propositions for functions
(and variable, classes...).

What exactly do you mean by "exist"? In each part of your sentence
here.
* I didn't mean anything by my "exist", I was just trying to transform
your statements into a general function form (instead nonstatic
member). So I was copying your "exist" word where you wrote them.

What members of 'a' are you referring to?
I don't want any misunderstandings, so: formally, we are referring to
the instance of type A which the identifier 'a' represents right?

itaj
 
P

Paul

itaj sherman said:
This is what I tried to explain. You say "called on an object" instead
"pass an object argument to the first parameter", but they mean the
exact same thing.


Yes.
And if you understand this, I think you should understand the rest of
what I said, if you read it carfully.


What is "func_pointer", and what is "invoke func_pointer"?
If you invoke a function (even through a pointer) you have to pass
arguments to all parameters, and you should state how you do it here.
That includes the special argument in case of a nonstatic member
function
class A{
public:
int foo(int arg){std::cout<< "in foo"; return arg;}
};

int main(){
int (A::*func_pointer)(int) = &A::foo;
A a;
(a.*func_pointer)(4); /*invoking*/
}
Which question?!
All the ones you talked about are.
Syntactic and name lookups are different.


I know you disagreed. This is exactly why I tried to explain how they
are the same, with respect to your issue.
I tried my best to explain. I think if you were able to grasp this
concept in a general way (instead just nonstatic members), it would
help you clear the confusions for you and everyone else.
I understand that you are saying that calling a function with an explicit
(reference to an object ) argument, is the same as calling a member function
with hidden argument.
I am a bit cautious to agree because I think there may be cases where this
is not always true. Perhaps some calling conventions differ and also I think
with virtuals the case is slightly different.

But putting those cases aside
I think you are correct to say that
afunct(&aObj) ;
cannot exist unless aObj exists.
 
P

Paul

itaj sherman said:
It depends on what exactly one means by function "exists".
I only ever used "declared" and "defined" propositions for functions
(and variable, classes...).

What exactly do you mean by "exist"? In each part of your sentence
here.
* I didn't mean anything by my "exist", I was just trying to transform
your statements into a general function form (instead nonstatic
member). So I was copying your "exist" word where you wrote them.

What members of 'a' are you referring to?
I don't want any misunderstandings, so: formally, we are referring to
the instance of type A which the identifier 'a' represents right?
Yes.
I agree the word 'exists' is a bit dubious.

To me a function exists if it has been declared and defined, but with
nonstatic member functions it is not so simple because they are undefined
unless called on an object.
I think it is techincally possible to invoke a nonstatic and nonvirtual
member function without an object, so therefore incorrect to say it does not
exist, but I also think this would be invalid code according to the
standard.
The lifetime of a function could be considered as starting from when it is
called until it returns, or it could be for as long as it is available for
calling. The true definition of a functions existence is dependant on this.
An object has a defined lifetime therefore I think it is correct to say an
object only exists during its lifetime. It follows that the existence of a
member function , called on said object, is dependant on the object existing
in the first place. This is what I was trying to express.

I think it is an acceptable concept to consider a member function part of an
object (I know a member function is not contained within an objects region
of memory, please don't go there).
Some others disagree about this and say that a member function is *only* a
member of a class and not a member of an object.
 
I

Ian Collins

Yes.
I agree the word 'exists' is a bit dubious.

To me a function exists if it has been declared and defined, but with
nonstatic member functions it is not so simple because they are
undefined unless called on an object.

How can something with a definition (the function body) be undefined?

If a member function is undefined without an instance of class, how can
one write

struct A { void foo() {} };

typedef void (A::*fnPtr)();

fnPtr fn = &A::foo;

Taking the address of something that's undefined?
I think it is techincally possible to invoke a nonstatic and nonvirtual
member function without an object, so therefore incorrect to say it does
not exist, but I also think this would be invalid code according to the
standard.

The code will be valid in order to compile, but calling it may result in
undefined behaviour.

void f( A* a ) { a->foo(); }

Is perfectly valid code.

f(NULL);

or

A* a;

f(a);

is also valid code, which results in undefined behaviour.
I think it is an acceptable concept to consider a member function part
of an object (I know a member function is not contained within an
objects region of memory, please don't go there).
Some others disagree about this and say that a member function is *only*
a member of a class and not a member of an object.

Just about everyone will disagree (hands up all who don't).
 
P

Paul

Ian Collins said:
How can something with a definition (the function body) be undefined?
Sorry I meant unless called on an object it's undefined *by the standard* ,
I should've been clearer.
If a member function is undefined without an instance of class, how can
one write

struct A { void foo() {} };

typedef void (A::*fnPtr)();

fnPtr fn = &A::foo;

Taking the address of something that's undefined?


The code will be valid in order to compile, but calling it may result in
undefined behaviour.
This is dependant on your defintion of "valid code", your idea of valid code
is different from OoTiib's.

What is your definiton of :
a) valid code
b) legal code

void f( A* a ) { a->foo(); }

Is perfectly valid code.

f(NULL);

or

A* a;

f(a);

is also valid code, which results in undefined behaviour.
If it results in undefined behaviour then there is obviously something wrong
with the code. What is valid and/or illegal code, if not code that produces
undefined behaviour ?
Just about everyone will disagree (hands up all who don't).
If you disagree with this then you also disagree with C++ supporting OOP.
Any language that supports OOP must support this concept.
 
P

Paul

Leigh Johnston said:
In C++ a member function is a member of a class not a member of an object;
in C++ an object is simply a region of storage; in C++ a non-static member
function is *invoked* on an object it is not part of an object.
Leigh's repetition of this nonsense does not make it correct.

Can he actually show some standard compliant code that calls a nonstatic
member function
a) on a class type
b) without and object.

No , as I thought he is just trolling nonsense as usual.
 
I

itaj sherman

I understand that you are saying that calling a function with an explicit
(reference to an object ) argument, is the same as calling a member function
with hidden argument.

Yeah. That's what I meant.
That I think it is beneficial to think of nonstatic member functions
this way. for example:
void A::foo( Par1, Par2 );
as a function of arity 2, with a first parameter of type A&, that is
special in the following properties:
- in the call syntax it is written before the function arg0.foo( arg1,
arg2 )
- the lookup for the function name is done only by that special
argument's type, and not by all the other (unlike global functions).
So the difference with global functions or static member function is
only in the call syntax and lookup rules, but nothing else.
* Except for that weird temporary bind to non-const reference
difference. I think they probabely should all been disallowed.

That is, such a function is equivalent to:
void foo( A&, Par1, Par2 );
foo( arg0, arg1, arg2 );

I think keeping in mind this equivalence would be beneficial for your
subjects of arguments' validity and any definition of existance.
I am a bit cautious to agree because I think there may be cases where this
is not always true. Perhaps some calling conventions differ and also I think
with virtuals the case is slightly different.

I'm not sure what you mean by "calling conventions".

However, the virtual case is more delicate to express but is not
different. There's still no inherent difference with global functions,
because:
In theory virtuality is a property of any certain parameter of a
function. I.e a few parameters of a certain function can be virtual -
such functions are called "multimethods". And again, theoretically it
does not matter if they are global, static members or nonstatic
members (that just changes the syntax). There are languages that have
this feature.
Although Stroustrup wanted to add this feature to c++ already before
1990, as he says in "The Design and Evolution of C++", the main reason
we don't have them in c++ by now, is not enough time to work on that,
due to other more important features they had to add.
I do believe it will be added one day to the language, though
probabely not even by c++1X.
This is a quite complicated feature to implement for a language. It
has been decided to restrict the virtuality feature in a way that
allows implementation of it to be much simpler, and that required:
- only 1 parameter of a function is allowed to be virtual
- any override of a function that is virtual on a certain parameter,
must be declared within the class type of this parameter. practically
then, it was very convenient to call them "virtual member functions",
and use the same syntax rules as nonstatic member functions.
And when we need multi-virtuality we use workaround idioms like multi-
dispatch.

For example, the multi-virtuality feature could look like:

class Carnivour {};
class Prey{};
void eat_prey( virtual Carnivour&, virtual Prey& ) = 0;

//overrides
class Lion: public Carnivour {};
class Anaconda: public Carnivour {};
class Bear: public Carnivour {};

class Girrafe: public Prey {};
class Gazelle: public Prey {};

void catch_prey( Lion&, Gazelle& ) { ... } //jumps on it and bite its
neck
void catch_prey( Lion&, Girrafe& ) { ... } //bite its ass
void catch_prey( Cobra&, Gazelle& ) { ... } //inject venom
//Anaconda can't kill girrafes so no override for that one
void catch_prey( Bear&, Prey& ) { ... } //because Bears catch
everything in the same way lol.
But putting those cases aside
I think you are correct to say that
afunct(&aObj) ;
cannot exist unless aObj exists.

I didn't say that it exists.
I say: if we define the meaning of "function exists" in a certain way,
then it should turn out the same for nonstatic member function as for
any reference parameter in any type of function.
But I don't know any definition for "function exists" and I don't know
what beneficial usage could be done with such definition.

itaj
 
I

Ian Collins

Leigh's repetition of this nonsense does not make it correct.

The nonsense is yours I'm afraid.
Can he actually show some standard compliant code that calls a nonstatic
member function
a) on a class type
b) without and object.

a.h:

struct A { void foo(); };

void f( A* a );

a.cc:

#include "a.h"

void A::foo() {}

void f( A* a ) { a->foo(); }

main.cc:

#include "a.h"

int main()
{
A a;

f(&a); // With object.
f(NULL); // Without object.
}
 
I

itaj sherman

Yes.
I agree the word 'exists' is a bit dubious.

To me a function exists if it has been declared and defined, but with
nonstatic member functions it is not so simple because they are undefined
unless called on an object.

I think you mean: "Without an objet the function invocation causes
undefined behaviour".

The "function definition" istelf has nothing to do with it.
The "function extistance" - depends how you define that.

However, this should be exactly the same as any reference parameter,
as in my example.
void foo( A& );
This function invocation without a valid object argument, will have
undefined behaviour.
Same as the nonstatic member function, and same as
I think it is techincally possible to invoke a nonstatic and nonvirtual
member function without an object, so therefore incorrect to say it does not
exist, but I also think this would be invalid code according to the
standard.
The lifetime of a function could be considered as starting from when it is
called until it returns, or it could be for as long as it is available for
calling. The true definition of a functions existence is dependant on this.
An object has a defined lifetime therefore I think it is correct to say an
object only exists during its lifetime. It follows that the existence of a
member function , called on said object, is dependant on the object existing
in the first place. This is what I was trying to express.

Well then, maybe for these definitions, the names "function invocation
lifetime" and "function invocation exists" would be better than
"function lifetime" and "function exists"?
I think "function exists" could be confusing.

For example, IMO, even the names chosen for definitions in the
standard are not the best ones:
data member
static data member
function member
static function member

What the difinitions are, is very clear and precise in the standard,
but the names chosen for them IMO are quite confusing.
- The use of the word "static" as such, suggests that the difference
between "data member" and "static data member" is the same as the
difference between "function member" and "static function member".
This isn't so, it's not the same at all.
- Even the use of the same word "member", suggest that data, static
data, and functions are all members - belong to somthing in the same
way. Totaly not. The meaning of the word member is totaly different.

I think better names would be instead:

subobject variable //data member
because it defines a certain subobject of every instance of that
class.

related variable //static data member
because is just like a single global variable, except it's related to
the class by scope.

attached function //function member
the function's call syntax and lookup is attached to the special first
argument which is written before the function name and is equivalent
to a reference of the class.

related function //static function member
just like a global function, but related to the class by scope

I wouldn't use misleading words like "member" and "static".
But there's no chance to change them in the standard after been used
so long.

itaj
 
I

itaj sherman

On 02/21/11 11:11 AM, Paul wrote:


a.h:

struct A { void foo(); };

void f( A* a );

a.cc:

#include "a.h"

void A::foo() {}

void f( A* a ) { a->foo(); }

main.cc:

#include "a.h"

int main()
{
   A a;

   f(&a);   // With object.
   f(NULL); // Without object.

I think this is undefined behaviour, even thought A::foo is empty.
inside f(),
a->foo()
is equivalent to:
(*a).foo()
which would be an indirection of NULL, undefined behaviour.
isn't it?

itaj
 
I

Ian Collins

I think this is undefined behaviour, even thought A::foo is empty.
inside f(),
a->foo()
is equivalent to:
(*a).foo()
which would be an indirection of NULL, undefined behaviour.
isn't it?

It may result in undefined behaviour, but there's nothing non standard
in the code. I put the declaration and definition in separate
compilation units to force the point. There is no way the compiler can
know about the working of f() when compiling main.cc.
 
I

itaj sherman

On 02/21/11 12:05 PM, itaj sherman wrote:


It may result in undefined behaviour, but there's nothing non standard
in the code. I put the declaration and definition in separate
compilation units to force the point. There is no way the compiler can
know about the working of f() when compiling main.cc.

That's true.
I'd think Paul meant code "with defined behaviour", not just "well
formed".
But then again, he didn't specify that clearly.
And as you mention in your previous post, he doesn't seem strict about
the difference between "defined" and "defined behaviour".

And his response to that certainly didn't clear that up:

Does Paul mean "undefined behaviour"?
Sorry I meant unless called on an object it's undefined *by the standard* ,
I should've been clearer.

Again, does Paul mean "undefined behaviour"?

itaj
 
J

Johannes Schaub (litb)

James said:
I don't quite follow you here. If I have a function:
void f(int&);
, it's undefined behavior for me to call f without a an object
of type int. The function f(int&) still "exists". For some
definition of "exists"---this is getting a bit too metaphysical
for me. One could argue that in C++, only "objects" exist, and
references and functions aren't objects, so can't "exist".

For me, only entities can "exist" and do exist (wiki: "An entity is
something that has a distinct, separate existence, although it need not be a
material existence."). In C++, functions and references are entities (in
C++03, a reference was not an entity yet, but has grown to be one in C++0x,
since the one definition rule also applies to references).

The identity of functions are their signature and I believe the identity of
objects is the tuple of (type, address) (address alone is not sufficient,
for example when you have an array, the first element has the same address
as its array).

I believe that everything that semantically "exists" in C++ needs to be
mentioned in the entity list, and usually needs to be mentioned in the one
definition rule (unless it can't apply to it, like "value"s and "parameter
pack"s). It's my own interpretation though. I'm not at all saying that your
model of "exists" is wrong or anything :)
 
J

Johannes Schaub (litb)

Paul said:
An object(instance of a class type) has a lifetime, it exists for the
duration of its lifetime.
Because C++ disallows calling nonstatic member functions, without an
object of , or derived from, the respective class type. A non static
member function cannot exist unless an object exists.

For some objects, they exist not only during their lifetime, but also
afterwards and previously: The lifetime of class objects start as soon as
their constructor finishes execution, and their lifetime stops as soon as
the destructor finishes execution. But the object already exists at the
start of the constructor execution and still exists until the destructor
stops execution.

The Standard is not actually clear about the existence-question of objects,
I think. I think you can say that for non-class objects, their lifetime
defines their existence. But for class objects, the definition is more
complicated. An alternative model I can see can be interpreted from the
Standard is that an object starts existence independently from starting its
lifetime. But this alternative model has serious trouble, including the
question how objects that are created by mere writes to storage (malloc +
write) come to existence.
 
J

Johannes Schaub (litb)

Paul said:
An object(instance of a class type) has a lifetime, it exists for the
duration of its lifetime.
Because C++ disallows calling nonstatic member functions, without an
object of , or derived from, the respective class type. A non static
member function cannot exist unless an object exists.

For some objects, they exist not only during their lifetime, but also
afterwards and previously: The lifetime of class objects start as soon as
their constructor finishes execution, and their lifetime stop as soon as
the destructor begins execution. But the object already exists at the
start of the constructor execution and still exists until the destructor
stops execution.

The Standard is not actually clear about the existence-question of objects,
I think. I think you can say that for non-class objects, their lifetime
defines their existence. But for class objects, the definition is more
complicated. An alternative model I can see can be interpreted from the
Standard is that an object starts existence independently from starting its
lifetime. But this alternative model has serious trouble, including the
question how objects that are created by mere writes to storage (malloc +
write) come to existence.
 
P

Paul

Ian Collins said:
It may result in undefined behaviour, but there's nothing non standard in
the code. I put the declaration and definition in separate compilation
units to force the point. There is no way the compiler can know about the
working of f() when compiling main.cc.

--
No the code is invalid ref:
"5.2.5 Class member access [expr.ref]
1 A postfix expression followed by a dot . or an arrow >,
optionally followed by the keyword template
(14.8.1), and then followed by an idexpression,
is a postfix expression. The postfix expression before the
dot or arrow is evaluated;55) the result of that evaluation, together with
the idexpression,
determine the
result of the entire postfix expression.
2 For the first option (dot) the type of the first expression (the object
expression) shall be "class object" (of a
complete type). For the second option (arrow) the type of the first
expression (the pointer expression) shall
be "pointer to class object" (of a complete type). In these cases, the
idexpression
shall name a member of
the class or of one of its base classes. [Note: because the name of a class
is inserted in its class scope (9),
the name of a class is also considered a nested member of that class. ]
[Note: 3.4.5 describes how names
are looked up after the . and >
operators. ]"


The above quote from the C++ standard states "the first expression (the
pointer expression) shall
be "pointer to class object" (of a complete type). ".
Your expression a->foo() , with a =NULL, is not valid C++ code.
 
I

itaj sherman

The above quote from the C++ standard states "the first expression (the
pointer expression) shall
be "pointer to class object" (of a complete type). ".
Your expression a->foo() , with a =NULL, is not valid C++ code.- Hide quoted text -

You never mentioned validity before.
The code is well formed.
May produce undefined behaviour.

itaj
 
I

Ian Collins

No the code is invalid ref:
"5.2.5 Class member access [expr.ref]

The above quote from the C++ standard states "the first expression (the
pointer expression) shall
be "pointer to class object" (of a complete type). ".
Your expression a->foo() , with a =NULL, is not valid C++ code.

Where did I write a->foo() , with a =NULL?

I wrote a->foo() with a being an A* which is a pointer to a complete type.

Point out exactly where the standard is violated in either of those two
compilation units.
 

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

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top