Topic: Some considerations on functions and constructors
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 2000/01/26 Raw View
alexy wrote:
[...]
> One potential difficulty for compiler writers is that 'f' or 'vc.begin'
> below are indeed expressions, not a type names as it is required by
> language now. And semantics of object's construction would become a
> dynamic - I mean if we write something like
>
> void foo( Animal (* ctor_func )() )
> {
> *ctor_func my_pet;
> my_pet.eat();
> }
>
> we can't say at a compile time what function will be used for 'my_pet'
> construction. Which is pretty cool ;)
[...]
> In fact I love your idea very much. It can resolve many questions,
> which appears here and in comp.lang.c++.moderated again and again over
> time - like 'typeof' or 'declare' proposals, 'new' and casts redundancy
> etc. (I would expect these constructs to work too:
>
> new Animal pet_ptr( "my cat" );
>
> dynamic_cast<My_widget*> my_widget_ptr( widget_ptr );
> )
>
> > (BTW, I know that the standard is fixed for the next five years.
> > But I expect the world still to exist then ;-))
> >
>
> I think we must work on it and I would love to taste it in a real code
> some day ;)
Looking on CD2, I think at least the grammar changes would be
simple:
For the "constructor as function" part, "primary-expression"
would get as new alternative "simple-type-specifier",
and in "postfix-expression", the alternative
"simple-type-specifier ( expression-listopt )" would be removed
since that rule now can be generated by
postfix-expression
-> postfix-expression ( expression-listopt )
-> primary-expression ( expression-listopt )
-> simple-type-specifier ( expression-listopt )
For the "function as type" part, in "decl-specifier" the
alternative "type-specifier" would have to be replaced by
a new symbol "decl-type-specifier". The replacement rule for
"decl-type-specifier" would look like the one for
"type-specifier" except that "simple-type-specifier"
would be replaced by "postfix-expression" (the revised
production rule for postfix-expression allows deduction
of simple-type-specifier, and the corresponding semantics
also results in the correct result).
Of course, all those grammmar changes would have to be
accompanied with the corresponding semantic description.
BTW, with this syntax, your first example would have to be
written as
void foo( Animal (* ctor_func )() )
{
(*ctor_func) my_pet;
my_pet.eat();
}
since *ctor_func is no postfix-expression, but (*ctor_func) is
(postfix-expression -> primary-expression -> ( expression ) -> ...)
Adding two alternatives for new and cast could in addition
allow the intuitive syntax you used for new and dynamic_cast.
For the latter, there could be two additional alternatives
for "decl-type-specifier" (see above), say "decl-new-specifier"
and "decl-cast-specifier", with the rules
decl-new-specifier:
::opt new new-placementopt new-type-id
::opt new new-placementopt ( type-id )
decl-cast-specifier:
dynamic_cast < type-id >
static_cast < type-id >
reinterpret_cast < type-id >
const_cast < type-id >
If there is more than one variable declared with the same
expression, the expression should of course be evaluated for
each of the variables; f.ex.
rand foo, bar, baz;
generates three different random numbers in foo, bar and baz,
and
sqrt r2(2), r3(3), r5(5);
initializes r2 with sqrt(2), r3 with sqrt(3) and r5 with sqrt(5).
An interesting special case is the following:
int foo(int);
double foo(char const*);
foo a(3), b("Hello world");
This would declare a to be int and b to be double.
In any case, in declarations, the only expressions allowed
are those which allow operator() applied, of course, and the
resulting expression may not be of type void. Also the
init-declarator(s) in that case should be restricted to
pure declarator-id(s) (i.e., declarations like "(*pfun) *p, f()"
should not be allowed - defining a meaningful semantics would
be hard for them anyway).
Definitions with copy initialisation should be allowed as well, for
orthogonality:
SomeClass f(int);
f someVar = 3; // exactly same as SomeClass someVar(f(3));
In this case, of course a copy constructor would be required
(although the copy may be optimized out as usual).
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 2000/01/22 Raw View
I've had some thoughts about constructors and value-returning
functions. The point is that each value-returning function is
indeed constructing an object of the return type. Therefore
for the caller, it could be viewed as "named constructor" which
can only be used to generate temporary objects (rvalues).
Furthermore, for creating a temporary object directly through
it's constructor, the type name is used exactly like a function
name. Finally, if looking "under the hood", we see that both
constructors and value-returning functions must be passed an
address where to construct the returned object (except for
functions returning small POD types, which can be done in
registers - but that's true for POD "constructors" anyway).
Given all this, there seems a wide equivalence between
constructors and value-returning functions. However, there
are AFAICS two differences:
- Constructors can be used to define named objects; functions
cannot
- Functions can be assigned to function pointers; constructors
cannot
My idea is that those two differences could be removed, therefore
allowing:
struct X
{
X();
X(int);
};
X f();
X f(double);
X x1; // default-construct x
f x2; // initialize x by call to f() (doesn't need accessible
// copy constructor, since x2 _is_ the return value of f)
f x3(); // The same (cannot be interpreted as function definition,
// since f is no type)
X x4(3); // construct x through X::X(int)
f x5(1.5); // initialize x through X f(double)
X (*p1)() = f; // function pointer p1 points to X f()
X (*p2)() = X; // function pointer p2 points to X::X()
X (*p3)(double) = f; // p3 points to X f(double)
X (*p4)(int) = X; // p4 points to X::X(int);
Since all of the new constructs currently would lead to a
syntax error, this would be pure language extension.
One nice thing about this is that it would automatically
include the "declare" or "var" feature (i.e. variable type
depending on type of assigned value):
int main()
{
std::vector<char> vc;
// fill vc
for (vc.begin iter(); iter != vc.end(); ++iter)
{
// ...
}
}
For general expressions, a "declare" function would work:
template<class T> T& declare(T& t) { return t; }
declare x(vec.begin()+10); // here declare is _not_ a keyword,
// but the name of the above function!
Any thoughts about this?
(BTW, I know that the standard is fixed for the next five years.
But I expect the world still to exist then ;-))
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: alexy <alexy@meta-comm.com>
Date: 2000/01/23 Raw View
In article <38881D20.F1328D27@physik.tu-muenchen.de>,
Christopher Eltschka <celtschk@physik.tu-muenchen.de> wrote:
> I've had some thoughts about constructors and value-returning
> functions. The point is that each value-returning function is
> indeed constructing an object of the return type. Therefore
> for the caller, it could be viewed as "named constructor" which
> can only be used to generate temporary objects (rvalues).
> Furthermore, for creating a temporary object directly through
> it's constructor, the type name is used exactly like a function
> name. Finally, if looking "under the hood", we see that both
> constructors and value-returning functions must be passed an
> address where to construct the returned object (except for
> functions returning small POD types, which can be done in
> registers - but that's true for POD "constructors" anyway).
>
> Given all this, there seems a wide equivalence between
> constructors and value-returning functions. However, there
> are AFAICS two differences:
>
> - Constructors can be used to define named objects; functions
> cannot
> - Functions can be assigned to function pointers; constructors
> cannot
>
> My idea is that those two differences could be removed, therefore
> allowing:
>
> struct X
> {
> X();
> X(int);
> };
>
> X f();
> X f(double);
>
> X x1; // default-construct x
> f x2; // initialize x by call to f() (doesn't need accessible
> // copy constructor, since x2 _is_ the return value of f)
> f x3(); // The same (cannot be interpreted as function definition,
> // since f is no type)
>
> X x4(3); // construct x through X::X(int)
> f x5(1.5); // initialize x through X f(double)
>
> X (*p1)() = f; // function pointer p1 points to X f()
> X (*p2)() = X; // function pointer p2 points to X::X()
> X (*p3)(double) = f; // p3 points to X f(double)
> X (*p4)(int) = X; // p4 points to X::X(int);
>
> Since all of the new constructs currently would lead to a
> syntax error, this would be pure language extension.
>
One potential difficulty for compiler writers is that 'f' or 'vc.begin'
below are indeed expressions, not a type names as it is required by
language now. And semantics of object's construction would become a
dynamic - I mean if we write something like
void foo( Animal (* ctor_func )() )
{
*ctor_func my_pet;
my_pet.eat();
}
we can't say at a compile time what function will be used for 'my_pet'
construction. Which is pretty cool ;)
> One nice thing about this is that it would automatically
> include the "declare" or "var" feature (i.e. variable type
> depending on type of assigned value):
>
> int main()
> {
> std::vector<char> vc;
> // fill vc
> for (vc.begin iter(); iter != vc.end(); ++iter)
> {
> // ...
> }
> }
>
> For general expressions, a "declare" function would work:
>
> template<class T> T& declare(T& t) { return t; }
>
> declare x(vec.begin()+10); // here declare is _not_ a keyword,
> // but the name of the above function!
>
> Any thoughts about this?
>
In fact I love your idea very much. It can resolve many questions,
which appears here and in comp.lang.c++.moderated again and again over
time - like 'typeof' or 'declare' proposals, 'new' and casts redundancy
etc. (I would expect these constructs to work too:
new Animal pet_ptr( "my cat" );
dynamic_cast<My_widget*> my_widget_ptr( widget_ptr );
)
> (BTW, I know that the standard is fixed for the next five years.
> But I expect the world still to exist then ;-))
>
I think we must work on it and I would love to taste it in a real code
some day ;)
--
-Alexy
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]