Topic: Two Proposals for the C++ Standard
Author: sbnaran@localhost.localdomain.COM (Siemel Naran)
Date: 1999/02/16 Raw View
On 15 Feb 99 14:23:44 GMT, Christopher Eltschka
>What about this (untested):
Your design calls for class MyClass to be a friend to class proxy.
This is so that class proxy can access the private MyClass get/set funcs.
Also, your class proxy contains pointers to the get/set functions as
private data members. This means that sizeof(proxy) is pretty big.
It also means that the constructor of class proxy should set these
data fields.
But there is an advanced feature of C++ that lets you get around these
restrictions. Use a pointer to a member function as a template
argument. One disadvantage is that you get extra template arguments.
To alleviate the long template argument lists, definitely use typedefs.
> // Constructor
> // I would like to make this private+friend, but befriending
> // a class given by template parameter is not legal :-(
Ie, this is illegal
template <class T> class X { friend class T; };
Can you think of a reason why?
I was thinking if we could use the proposed typeof operator to make
writing long typdefs easier. Eg, we could writet something like this
typedef typeof(std::bind2nd(std::plus<int>(),3)) UnaryFunction;
Applying this to the code below, I want to rewrite
typedef Proxy<Example,int,&getter,&setter> value_type;
as something like this:
typedef typeof(make_Proxy(&getter,&setter)) value_type;
IOW, can template argument deduction deduce non-type template arguments?
Como compiles the code below, but egcs does not.
template
<class Class, class T,
T (Class::*get)() const,
void (Class::*set)(const T&)
>
class Proxy
{
public:
explicit Proxy(Class& c_) : c(c_) { }
operator T() const { return (c.*get)(); }
void operator=(const T& t) { /*return*/ (c.*set)(t); }
private:
Class& c;
};
class Example
{
private:
int d_value;
int getter() const { return d_value; }
void setter(const int& value) { d_value=value; }
public:
typedef Proxy<Example,int,&getter,&setter> value_type;
Example() : d_value() { }
value_type value() { return value_type(*this); }
};
//
#include <iostream>
int main()
{
Example e;
cout << e.value() << '\n';
e.value()=5;
cout << e.value() << '\n';
}
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
[ 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: "Andrei Alexandrescu" <alexandrescua@micromodeling.com>
Date: 1999/02/17 Raw View
Siemel Naran wrote in message ...
>Ie, this is illegal
> template <class T> class X { friend class T; };
>Can you think of a reason why?
I tried this with MSVC 5:
template <class T> class X { friend T; };
and it worked!
>I was thinking if we could use the proposed typeof operator to make
>writing long typdefs easier.
I also like typeof a *whole* lot. In the last decade language design has
shifted a lot towards compile-time stuff. I guess this is because of
improvements in compiler technology. Look at ML for instance. I dream of a
language in which I can express problem-specific invariants and rules and
have the compiler (not the runtime system) check them.
Your typeof keyword would enable compile-time-heavy stuff. The compiler
support is already there - look at sizeof. Basically for the compiler to
evaluate a sizeof, it has to figure out the exact type of the expression.
One can do amazing things with sizeof alone, so I'm sure typeof would be
even more interesting.
Just for the sake of it, I really dislike the fact that
f().member
evaluates f() even if 'member' is a static member or an enumeration. ARM C++
did not evaluate f(), enabling one to do very interesting compile-time
deductions. They said it would be misleading, but what great feature does
not have its caveats? And besides, the precedent exists - sizeof(f().member)
doesn't evaluate anything, and that could also be dubbed as misleading. The
bigger the gun, the bigger the bullet, the more power you have, yet the more
you are at risk of blowing your foot away.
Andrei
[ 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: sbnaran@fermi.ceg.uiuc.edu (Siemel Naran)
Date: 1999/02/17 Raw View
On 17 Feb 1999 17:57:33 GMT, Andrei Alexandrescu
>Siemel Naran wrote in message ...
>I tried this with MSVC 5:
>
>template <class T> class X { friend T; };
>
>and it worked!
Since the standard does not allow you to make a class a friend to a
template argument, I don't think the code above should be allowed.
However, I don't see any harm in making the above code, even with the
"class" specifier, valid.
>Just for the sake of it, I really dislike the fact that
>
>f().member
No, f() must be evaluated because it may have side effects.
If we want an integral constant, then we should do this
typeof(f())::member
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
[ 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: 1999/02/15 Raw View
Philip Koester wrote:
[...]
> without the ugly-looking `get_' and `set_' prefixes. Using proxy classes is
> an elegant solution here, thanks for the suggestion, but may imply more
> typing work and less readable headers. What I am going to do now is look
> for a way to create generic proxy classes.
What about this (untested):
template<class T> T const& Const(T const& t) { return t; }
template<class Class, class Member> class Proxy
{
public:
// Constructor
// I would like to make this private+friend, but befriending
// a class given by template parameter is not legal :-(
Proxy(Class* c,
Member (Class::* getter)() const,
void (Class::* setter)(Member m),
):
theClass(c),
theGetter(getter),
theSetter(setter)
{
}
// Accessors:
operator Member() { return (theClass->*theGetter)(); }
void operator=(Member m) { return (theClass->*theSetter)(); }
private:
Class theClass;
Member (Class::* theGetter)() const;
void (Class::* theSetter)();
};
// Example usage:
class Example
{
friend class Proxy<Example, int>;
public:
Proxy<Example, int> value()
{
return Proxy<Example, int>(this,
&Example::get_value,
&Example::set_value);
}
private:
int get_value() { return theValue; }
void set_value(int t) { theValue = t<100? t : 100; }
int theValue;
};
Example x;
int main()
{
x.value()=5; // calls Example::set_value(5)
int a=x.value(); // calls Example::get_value();
}
---
[ 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: Valentin Bonnard <bonnard@clipper.ens.fr>
Date: 1999/02/15 Raw View
Philip Koester wrote:
>
> I don't have a profound insight on all facets of the C++ language, so please
> forgive me if the following has either been widely discussed already or is
> senseless for obvious reasons.
>
> Proposal 1: Allow omitting leading default arguments
>
> Given a function declared as `void foo(int a = 1, int b = 2, int c = 3);',
> it would make sense to me to be able to call it by saying `foo(,, 4);' if
> all I want is have the third argument differ from its default value. The
> way C++ is now, I need to say `foo(1, 2, 4);', which leads to a duplication
> of constant values that could be avoided.
In BASIC I was able to write CIRCLE (50,50),100,,,.8
(draw a circle; center = (50,50), radius = 100, it isn't a
circle, it's an ellipse with value .8 (don't ask me what it
means))
I hope I won't have to do it again.
So: no, forget it.
> Proposal 2: Let the compiler prefer const overloads over non-const
>
> Given a class A like this:
>
> class A {
> int _foo;
> public:
> A(int foo) : _foo(foo) {}
> int& foo() {return _foo;} // read/write access
> const int& foo() const {return _foo;} // read access
> };
Avoid leading underscores.
How can you define it:
- w/o breaking every C++ program
- with all the other overloading rules
Conclusion: forget it
--
Valentin Bonnard
[ 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: David R Tribble <dtribble@technologist.com>
Date: 1999/02/14 Raw View
Al Stevens wrote:
>
>> I was thinking of it for a bit. Bjarne also used to say that ",,"
>> can be the result of a typo.
>
> So can a semicolon, but we keep it in the language.
>
> if (a == b);
Yes, but most instances of ;; are benign.
void foo()
{{
Type * p;;
p = new((nothrow)) Type;;
if ((p == NULL))
{{
error(("Can't create Type"));;
return;;
}}
glob = p;;
p->bar((1));;
p->frob((2));;
}}
Offhand, I can't think of any instances where ,, would be (or
should be) benign.
-- David R. Tribble, dtribble@technologist.com --
---
[ 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: David R Tribble <dtribble@technologist.com>
Date: 1999/02/14 Raw View
Francis Glassborow wrote:
>
> Siemel Naran <sbnaran@localhost.localdomain> writes
> >>"Andrei Alexandrescu" <alexandrescua@micromodeling.com> writes:
> >
> > void foo(int =1 ,int =2 ,int=3);
> > void foo(double=1.0,double=2.0,int=3);
> >
> >>| foo(default, default, 4);
> >
> > Which foo(...) is called?
>
> but the same question can be asked of:
> foo();
>
> You cannot default all the parameters (or even all the trailing
> parameters if the leading ones have a common sequence of types.
Perhaps extending the syntax a little in order to allow for
resolution of ambiguities:
foo(default int, default, 4);
But maybe we've gone overboard here... I agree with Steve Clamage:
> The real problem is that default parameters interact badly
> with overloading, and proposals such as this one just make
> it worse. IMHO, we don't really need more opportunities for
> ambiguous function calls.
-- David R. Tribble, dtribble@technologist.com --
---
[ 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: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1999/02/10 Raw View
>"Andrei Alexandrescu" <alexandrescua@micromodeling.com> writes:
void foo(int =1 ,int =2 ,int=3);
void foo(double=1.0,double=2.0,int=3);
>| foo(default, default, 4);
Which foo(...) called?
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ 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: AllanW@my-dejanews.com
Date: 1999/02/10 Raw View
In article <36C02ADE.FBEAD9B3@physik.tu-muenchen.de>,
Christopher Eltschka <celtschk@physik.tu-muenchen.de> wrote:
>
> AllanW@my-dejanews.com wrote:
>
> [...]
>
> > Consider a similar version:
[snip]
>
> This code is illegal: You cannot overload functions which differ
> only in their return type.
Oh, nuts; this simple error obscured my whole point. Here's what
I meant to post.
class B {
int _bar;
friend void show_B(const B&);
public:
B(int);
int &bar();
int &baz();
const int bar() const;
const int baz() const;
};
// ...
B b(13);
int b = b.bar();
Now, the function that takes a const B reference will call
the const versions of bar() and baz().
----
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
---
[ 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: Philip Koester <kozmik@okay.net>
Date: 1999/02/10 Raw View
OK, many valuable contributions have been made, and I think this discussion
has come to an end. Thanks to everyone.
Proposal 1: Allow omitting leading default arguments
The solution `foo(,, 4);' doesn't seem appropriate because it may lead to
typos passing the compiler. (Of course there are other language features
that are just as bad, but that doesn't mean we should be arbitrary about
adding new ones.) Personally I prefer the suggestion to say `foo(default,
default, 4);' -- for three reasons:
1. It solves the problem (no values being duplicated).
2. It's explicit and robust.
3. It doesn't add a new keyword.
Anyone backing me here?
Proposal 2: Let the compiler prefer const overloads over non-const
The killer objection here is that this would break the current overloading
rules. Period. Using const objects or const casts (resp. const cast
templates) is a solution, and maybe what it's worth is that it makes us even
more aware of the dramatic differences that can arise from the presence or
absence of constness. You may say that is obvious, but problems like these
come in a new disguise every day.
How did I get to making this proposal? I was thinking of private data
members that come along with public member functions for reading and writing
to be a an object's `properties'. Reading a property, in most cases, will
lead to no other code than a simple `return', whereas reassigning might
require some checking for valid values, status updates and other things.
The obvious approach here is to make two functions for a property:
`get_property()' and `set_property()'. I was wondering if I could get away
without the ugly-looking `get_' and `set_' prefixes. Using proxy classes is
an elegant solution here, thanks for the suggestion, but may imply more
typing work and less readable headers. What I am going to do now is look
for a way to create generic proxy classes.
Again, thanks to everyone!
Philip Koester
---
[ 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: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/02/10 Raw View
In article <slrn7c0tvl.ij9.sbnaran@localhost.localdomain>, Siemel Naran
<sbnaran@localhost.localdomain> writes
>>"Andrei Alexandrescu" <alexandrescua@micromodeling.com> writes:
>
>void foo(int =1 ,int =2 ,int=3);
>void foo(double=1.0,double=2.0,int=3);
>
>>| foo(default, default, 4);
>
>Which foo(...) called?
but the same question can be asked of:
foo();
You cannot default all the parameters (or even all the trailing
parameters if the leading ones have a common sequence of types.
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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: Gabriel Dos_Reis <gdosreis@sophia.inria.fr>
Date: 1999/02/10 Raw View
James Kuyper <kuyper@wizard.net> writes:
--------------------
| > Very interesting... But then why not write out these arguements ?
|
| Because you want the default behavior, while wanting to leave the
| definition of the default behavior up to foo().
--------------------
What is the behaviour in case of overloading ?
Specifying the arguments selects the right function. Thus the proposal
in its actual form would be of very limited use.
--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr
[ 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: stephen.clamage@sun.com (Steve Clamage)
Date: 1999/02/11 Raw View
Francis Glassborow <francis@robinton.demon.co.uk> writes:
>In article <slrn7c0tvl.ij9.sbnaran@localhost.localdomain>, Siemel Naran
><sbnaran@localhost.localdomain> writes
>>>"Andrei Alexandrescu" <alexandrescua@micromodeling.com> writes:
>>
>>void foo(int =1 ,int =2 ,int=3);
>>void foo(double=1.0,double=2.0,int=3);
>>
>>>| foo(default, default, 4);
>>
>>Which foo(...) called?
>but the same question can be asked of:
>foo();
>You cannot default all the parameters (or even all the trailing
>parameters if the leading ones have a common sequence of types.
Here's a hypothetical example without those faults:
void foo(int = 1, double = 2.0, int);
void foo(double = 3.0, int = 4 , int);
foo(default, default, 5); // which foo?
It's easy to say, "OK, that case is ambiguous, but we'll keep
the feature."
The real problem is that default parameters interact badly
with overloading, and proposals such as this one just make
it worse. IMHO, we don't really need more opportunities for
ambiguous function calls.
In addition, default arguments have their own sets of
problems. For one thing, the binding of default arguments
sometimes surprises programmers.
extern int i;
...
int foo(int = i); // default is the global i
...
int bar()
{
int i = 3;
foo(); // incorrectly thinks 3 is the default value
...
}
For another, you can accidently have different defaults for the
same function in different files and get an unexpected result.
(To be fair, having different sets of overloaded function
declarations in different translation units can also cause surprises.)
It's worth noting that default parameters appeared originally
in C++ because function overloading at the time was difficult
to use and error-prone. You had to ensure that all declarations
for all overloads of a function appeared in the same sequence
in every translation unit. The invention of type-safe linkage
in 1989 ("name mangling") removed that difficulty.
You can usually get the same effect with function overloading
that you would otherwise get with default parameter values.
Simple example with "forwarding functions": Instead of
int foo(int=1, double=2.0);
you can write
int foo(int, double); // the "real" function
inline int foo(int j) { return foo(j, 2.0); }
inline int foo(double d) { return foo(1, d); }
inline int foo() { return foo(1, 2.0); }
This forwarding-function technique doesn't have the inline
advantage for virtual functions, and can't be used at all for
constructors. In those cases you have to repeat code or
call a common subroutine.
Lawrence Crowl has suggested the language be extended to allow
"forwarding constructors". Example:
class T {
T(int); // the "real" constructor
T() : T(3) { } // forwarding constructor
This pair of constructors would have the effect of
T(int=3)
I don't see any problems with this extension, although one
compiler writer said he didn't see how to implement it. (When
this particular person can't see a way to implement it, I assume
I have missed something.) If feasible, it would go a long way to
elmininating the need for default arguments.
--
Steve Clamage, stephen.clamage@sun.com
[ 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: "Philip Koester" <kozmik@okay.net>
Date: 1999/02/07 Raw View
I don't have a profound insight on all facets of the C++ language, so please
forgive me if the following has either been widely discussed already or is
senseless for obvious reasons.
Proposal 1: Allow omitting leading default arguments
Given a function declared as `void foo(int a = 1, int b = 2, int c = 3);',
it would make sense to me to be able to call it by saying `foo(,, 4);' if
all I want is have the third argument differ from its default value. The
way C++ is now, I need to say `foo(1, 2, 4);', which leads to a duplication
of constant values that could be avoided.
Proposal 2: Let the compiler prefer const overloads over non-const
Given a class A like this:
class A {
int _foo;
public:
A(int foo) : _foo(foo) {}
int& foo() {return _foo;} // read/write access
const int& foo() const {return _foo;} // read access
};
Why is it when I say `A a(13); int n = a.foo();' that always the non-const
foo() member function is chosen (tested with egcs 1.1.1 and VC5)? Bearing
in mind that const member functions can often be implemented more
efficiently than their non-const counterparts (e.g. write access to classes
implementing reference counting) -- wouldn't it be desirable to have the
const member function chosen here?
OK, when I say `const A a(13); ...', everything's fine of course, but
declaring stack objects as `const' isn't an all too common programming
technique for everyone, and even experienced programmers easily forget to do
so.
Regards,
Philip Koester
---
[ 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: "Andrei Alexandrescu" <alexandrescua@micromodeling.com>
Date: 1999/02/08 Raw View
Steve Clamage wrote in message <36c00372.834249775@news.earthlink.net>...
[snip]
>Using comma place-holders is too subject to simple and hard-to-find
>errors -- the lone comma is easy to overlook, leading to legal code
>that has the wrong meaning.
[snip]
I was thinking of it for a bit. Bjarne also used to say that ",," can be the
result of a typo.
What about using an explicit placeholder in there? Like:
foo(!, !, 4);
or
foo(?, ?, 4);
or the more verbose, but very suggestive:
foo(default, default, 4);
Andrei
---
[ 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: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1999/02/08 Raw View
On 07 Feb 99 17:56:21 GMT, Philip Koester <kozmik@okay.net> wrote:
>Proposal 1: Allow omitting leading default arguments
>
>Given a function declared as `void foo(int a = 1, int b = 2, int c = 3);',
>it would make sense to me to be able to call it by saying `foo(,, 4);' if
>all I want is have the third argument differ from its default value. The
>way C++ is now, I need to say `foo(1, 2, 4);', which leads to a duplication
>of constant values that could be avoided.
This sounds fine.
It might lead to code that is slightly harder to read.
But if properly used, it seems fine.
Sometimes, this alternative works
struct foo {
static int default_a() { return 1; }
static int default_b() { return 2; }
static int default_c() { return 3; }
void action(int a, int b, int c) const; // can be a static function
};
Sometimes, this works, but it relies on the optimizer optimizing away
unnecessary initializations:
class foo {
int a,b,c;
public:
foo() : a(1),b(2),c(3) { }
foo& seta(int a) { foo::a=a; return *this; }
foo& setb(int b);
foo& setc(int c);
void operator()() const;
};
There was also a proposal for named arguments, explained in D&E.
Something like this:
void foo(int a:=1, int b:=2, int c:=3);
int main() { foo(b:=3); } // call foo(1,3,3)
>Proposal 2: Let the compiler prefer const overloads over non-const
This is usually not necessary because we usually pass objects to
functions, and the function can receive the object as a const object
or as a reference to const. Example 1,
void foo1(const Object&); // declaration
void foo1(const Object& o) { } // definition
Example 2,
void foo2(Object); // declaration
void foo2(const Object o) { } // definition
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ 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: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/02/08 Raw View
In article <79kjob$qkg$1@news.ipf.de>, Philip Koester <kozmik@okay.net>
writes
>I don't have a profound insight on all facets of the C++ language, so please
>forgive me if the following has either been widely discussed already or is
>senseless for obvious reasons.
>
>Proposal 1: Allow omitting leading default arguments
>
>Given a function declared as `void foo(int a = 1, int b = 2, int c = 3);',
>it would make sense to me to be able to call it by saying `foo(,, 4);' if
>all I want is have the third argument differ from its default value. The
>way C++ is now, I need to say `foo(1, 2, 4);', which leads to a duplication
>of constant values that could be avoided.
The problem with your specific example is that all the parameters are of
the same type which makes it harder to substitute overloading forwarding
functions as a solution. For example
void foo(char first = 'c', int second = 24, double third = 1.3);
inline void foo (int second, double third = 1.3)
{ return foo('c', second, third); }
inline void foo(double third) { return foo('c', 24, third);}
inline void (char first, double third) { return foo(first,24,third);}
I think covers the eight options. I do not know why C++ chose the rule
that it did, but in fact default arguments are rarely more than a bit of
syntactic sugar except for ctors.
>
>Proposal 2: Let the compiler prefer const overloads over non-const
>
>Given a class A like this:
>
>class A {
> int _foo;
>public:
> A(int foo) : _foo(foo) {}
> int& foo() {return _foo;} // read/write access
> const int& foo() const {return _foo;} // read access
>};
>
>Why is it when I say `A a(13); int n = a.foo();' that always the non-const
>foo() member function is chosen (tested with egcs 1.1.1 and VC5)? Bearing
>in mind that const member functions can often be implemented more
>efficiently than their non-const counterparts (e.g. write access to classes
>implementing reference counting) -- wouldn't it be desirable to have the
>const member function chosen here?
True, but how do you propose we call the non-const version when that is
the one intended. You see, if the programmer has provided both it is
probable that both will be useful. The rule as it currently works says
'if the object is const then it must only call const member functions.'
However if the object is non-const it should call the function that does
not add a constraint. If you want to add it as a programmer then it
should be by conscious and explicit choice.
Your version requires that a mechanism be provided to explicitly select
the non-const version -- what are you proposing?
>
>OK, when I say `const A a(13); ...', everything's fine of course, but
>declaring stack objects as `const' isn't an all too common programming
>technique for everyone, and even experienced programmers easily forget to do
>so.
>
But, I think your proposal cripples the work of responsible programmers.
BTW where a member function is overloaded on const the two
implementations should do substantially the same thing, you just get
some extra protection where you have a const qualified object.
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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: Gabriel Dos_Reis <gdosreis@sophia.inria.fr>
Date: 1999/02/08 Raw View
"Philip Koester" <kozmik@okay.net> writes:
[...]
=B7------------------
| Proposal 2: Let the compiler prefer const overloads over non-const
|=20
| Given a class A like this:
|=20
| class A {
| int _foo;
| public:
| A(int foo) : _foo(foo) {}
| int& foo() {return _foo;} // read/write access
| const int& foo() const {return _foo;} // read access
| };
|=20
| Why is it when I say `A a(13); int n =3D a.foo();' that always the non-=
const
| foo() member function is chosen (tested with egcs 1.1.1 and VC5)? Bear=
ing
| in mind that const member functions can often be implemented more
| efficiently than their non-const counterparts (e.g. write access to cla=
sses
| implementing reference counting) -- wouldn't it be desirable to have th=
e
| const member function chosen here?
=B7------------------
Please a look at=20
=09
"Design and Evolution of C++"
Bjarne Stroustrup, 19954 Addison-Wesley
section 3.7 (about reference) and related for a thorough discussion.
--=20
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr
---
[ 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: stephen.clamage@sun.com (Steve Clamage)
Date: 1999/02/08 Raw View
On 07 Feb 99 17:56:21 GMT, "Philip Koester" <kozmik@okay.net> wrote:
>I don't have a profound insight on all facets of the C++ language, so please
>forgive me if the following has either been widely discussed already or is
>senseless for obvious reasons.
>
>Proposal 1: Allow omitting leading default arguments
>
>Given a function declared as `void foo(int a = 1, int b = 2, int c = 3);',
>it would make sense to me to be able to call it by saying `foo(,, 4);' if
>all I want is have the third argument differ from its default value. The
>way C++ is now, I need to say `foo(1, 2, 4);', which leads to a duplication
>of constant values that could be avoided.
Similar proposals surface about twice a year. The C++ Committee
seriously considered a few different versions over the course of about
two years.
Using comma place-holders is too subject to simple and hard-to-find
errors -- the lone comma is easy to overlook, leading to legal code
that has the wrong meaning.
The superior alternative is to used named argument values, as in Ada
and other languages. The problem there is that it has serious
interactions with function overloading. If you search Deja News, you
should be able to find lots of discussions.
Perhaps we ought to add this question to the comp.std.c++ FAQ.
>
>Proposal 2: Let the compiler prefer const overloads over non-const
>
>Given a class A like this:
>
>class A {
> int _foo;
>public:
> A(int foo) : _foo(foo) {}
> int& foo() {return _foo;} // read/write access
> const int& foo() const {return _foo;} // read access
>};
>
>Why is it when I say `A a(13); int n = a.foo();' that always the non-const
>foo() member function is chosen (tested with egcs 1.1.1 and VC5)?
Because the const on the member function refers to the hidden "this"
parameter, by definition. If you call foo on a non-const object, the
best match is on the non-const version of foo. If you call foo on a
const object, the best match is on the const version of foo.
If the const version is always perferred, how would you go about
calling the non-const version?
If you have const and non-const versions of a function, but prefer the
const version always to be called when possible, give the functions
different parameter lists. Normal overloading will then select the
appropriate version.
---
Steve Clamage, stephen.clamage@sun.com
---
[ 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: "Al Stevens" <alstevens@midifitz.com>
Date: 1999/02/09 Raw View
>I was thinking of it for a bit. Bjarne also used to say that ",," can be
the
>result of a typo.
So can a semicolon, but we keep it in the language.
if (a == b);
[ 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: "Philip Koester" <kozmik@okay.net>
Date: 1999/02/09 Raw View
Thanks for the replies.
Siemel Naran wrote:
>void foo2(Object); // declaration
>void foo2(const Object o) { } // definition
This way of having the declaration differ from the definition is actually
new to me. It's not part of the class's interface but adds some security
for the implementation -- I do see a use for that. However, my foo()
methods don't expect any arguments, and there is a reason for this. I will
explain below.
Francis Glassborow wrote:
>True, but how do you propose we call the non-const version when that is
>the one intended.
By saying `a.foo() = 2;'!
>But, I think your proposal cripples the work of responsible programmers.
>BTW where a member function is overloaded on const the two
>implementations should do substantially the same thing, you just get
>some extra protection where you have a const qualified object.
Yes agreed, this is right for the current standard and is exactly what I
criticize.
Look at this example. Provided that std::string is implemented in a way
that it can share data across different objects:
string s1 = "Philip";
cout << (void*) s1.c_str() << endl; // Address of "Philip"
string s2 = s1;
cout << (void*) s2.c_str() << endl; // Another string object, same address
char c = s2[0]; // "Read" a character from s2
cout << (void*) s2.c_str() << endl; // New address!
What happens here is by the time the operator [] is called, a new char
buffer is allocated because the string class has no chance to predict if the
returned char& is subject to reading or writing. Only declaring s2 by
"const string s2 = s1;" solves this problem. As I already mentioned,
programmers are likely to overlook this subtlety. However, as the return
value of operator [] is *copied* to a char, I don't see a reason why the
non-const flavor of that operator should be chosen here.
I guess there is already a fair amount of code around that suffers from this
problem.
Gabriel Dos Reis wrote:
>Please a look at
>"Design and Evolution of C++"
>Bjarne Stroustrup, 19954 Addison-Wesley
You got me there, Gabriel. I'm off to buy this book today =)
As for my first proposal, Steve Clamage wrote:
>Using comma place-holders is too subject to simple and hard-to-find
>errors -- the lone comma is easy to overlook, leading to legal code
>that has the wrong meaning.
A reasonable objection. At the end of the day, this issue isn't really
vital for me. Yet the duplication of values here that might force me to
scan my .cc files whenever I change a leading default argument in a header
is not acceptable. The only way to avoid this is simply not to use this
language feature. And, after all, wouldn't you immediately get stuck on a
line like `foo(, whatever)'?
Regards,
Philip Koester
[ 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: Gabriel Dos_Reis <gdosreis@sophia.inria.fr>
Date: 1999/02/09 Raw View
"Andrei Alexandrescu" <alexandrescua@micromodeling.com> writes:
=B7--------------------
| I was thinking of it for a bit. Bjarne also used to say that ",," can b=
e the
| result of a typo.
| What about using an explicit placeholder in there? Like:
|=20
| foo(!, !, 4);
|=20
| or
|=20
| foo(?, ?, 4);
|=20
| or the more verbose, but very suggestive:
|=20
| foo(default, default, 4);
=B7--------------------
Very interesting... But then why not write out these arguements ?
--=20
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr
---
[ 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: AllanW@my-dejanews.com
Date: 1999/02/09 Raw View
In article <79kjob$qkg$1@news.ipf.de>,
"Philip Koester" <kozmik@okay.net> wrote:
> I don't have a profound insight on all facets of the C++ language, so please
> forgive me if the following has either been widely discussed already or is
> senseless for obvious reasons.
>
> Proposal 1: Allow omitting leading default arguments
>
> Given a function declared as `void foo(int a = 1, int b = 2, int c = 3);',
> it would make sense to me to be able to call it by saying `foo(,, 4);' if
> all I want is have the third argument differ from its default value. The
> way C++ is now, I need to say `foo(1, 2, 4);', which leads to a duplication
> of constant values that could be avoided.
When I first saw this rule, I was a bit annoyed, but I assumed
that there must be a good reason for it. I never did find out
what the reason was, but I can tell you that it never has been
as much of an annoyance as I assumed it would be.
> Proposal 2: Let the compiler prefer const overloads over non-const
>
> Given a class A like this:
>
> class A {
> int _foo;
> public:
> A(int foo) : _foo(foo) {}
> int& foo() {return _foo;} // read/write access
> const int& foo() const {return _foo;} // read access
> };
>
> Why is it when I say `A a(13); int n = a.foo();' that always the non-const
> foo() member function is chosen (tested with egcs 1.1.1 and VC5)?
Consider a similar version:
class B {
int _bar;
friend void show_B(const B&);
public:
B(int);
int &bar();
int &baz();
const int bar();
const int baz();
};
// ...
B b(13);
int b = b.bar();
I'm sure you can see that this MIGHT be the same thing, except
without the functions declared inline. On the other hand the
member functions might not be obvious at all. Since we don't
know if bar() modifies b or not, how can we call the const
version?
> Bearing
> in mind that const member functions can often be implemented more
> efficiently than their non-const counterparts (e.g. write access to classes
> implementing reference counting) -- wouldn't it be desirable to have the
> const member function chosen here?
Only if the compiler was *CERTAIN* that the const version and the
non-const version were semantically the same thing. In practice
this never happens. If the compiler were to assume that they
accomplish the same thing, it would break some valid C++ programs.
> OK, when I say `const A a(13); ...', everything's fine of course, but
> declaring stack objects as `const' isn't an all too common programming
> technique for everyone, and even experienced programmers easily forget to do
> so.
What isn't so rare is const references or pointers:
void show_B(const B&b) {
std::cout << "B(_bar=" << b._bar
<< ",bar()=" << b.bar()
<< ",baz()=" << b.baz()
<< ')' << std::endl;
}
This calls the const member functions.
----
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
---
[ 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: Jens Kilian <Jens_Kilian@bbn.hp.com>
Date: 1999/02/09 Raw View
> From: Gabriel Dos_Reis <gdosreis@sophia.inria.fr>
> Very interesting... But then why not write out these arguements ?
Possible application (please note: I would NEVER write code like this IRL):
class foo {
public:
void fun(int i = 0, int j = 42);
};
class bar {
public:
void fun(int i = 1, int j = 42);
};
template <class T> void baz(T zip)
{
zip.fun(default, 4711); // Use of default first argument.
}
Regards,
Jens.
--
mailto:jjk@acm.org phone:+49-7031-14-7698 (HP TELNET 778-7698)
http://www.bawue.de/~jjk/ fax:+49-7031-14-7351
PGP: 06 04 1C 35 7B DC 1F 26 As the air to a bird, or the sea to a fish,
0x555DA8B5 BB A2 F0 66 77 75 E1 08 so is contempt to the contemptible. [Blake]
[ 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: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/02/09 Raw View
In article <xaj7ltstjrh.fsf@korrigan.inria.fr>, Gabriel Dos_Reis
<gdosreis@sophia.inria.fr> writes
>Very interesting... But then why not write out these arguements ?
Perhaps because you do not know them, nor need to know them. Look at
the C++SL and you will find cases of counter-intuitive orderings of
parameters in order to ensure that the one that will usually be
defaulted comes last.
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ 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: 1999/02/09 Raw View
AllanW@my-dejanews.com wrote:
[...]
> Consider a similar version:
>
> class B {
> int _bar;
> friend void show_B(const B&);
> public:
> B(int);
> int &bar();
> int &baz();
> const int bar();
> const int baz();
> };
> // ...
> B b(13);
> int b = b.bar();
This code is illegal: You cannot overload functions which differ
only in their return type.
[...]
[ 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: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/02/09 Raw View
In article <79nuoc$pl1$1@news.ipf.de>, Philip Koester <kozmik@okay.net>
writes
>By saying `a.foo() = 2;'!
Does not work without making substantial changes elsewhere. The name
lookup and overload resolution rules are complicated enough already
without adding this kind of contextual inference.
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ 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: 1999/02/09 Raw View
Philip Koester wrote:
>
> Thanks for the replies.
>
> Siemel Naran wrote:
>
> >void foo2(Object); // declaration
> >void foo2(const Object o) { } // definition
>
> This way of having the declaration differ from the definition is actually
> new to me. It's not part of the class's interface but adds some security
> for the implementation -- I do see a use for that. However, my foo()
> methods don't expect any arguments, and there is a reason for this. I will
> explain below.
>
> Francis Glassborow wrote:
>
> >True, but how do you propose we call the non-const version when that is
> >the one intended.
>
> By saying `a.foo() = 2;'!
But the " ... = 2" is only considered _after_ the foo() has been
selected. Indeed, in general it might depend on the foo that was
selected. Think of a class returning a proxy object from foo() const.
Then, to decide which method to choose, it would have to examine
that proxy objewct, if it has defined an operator= taking an
argument, which itself is either int, const int& or any object type
which can be converted to int. To make it short: This would mean
overloading on the _return type_ (since only that determines if
assignment to a.foo() is allowed; the returned object/reference
needs not to be part of the object itself), with all the
complexities that result. Not that it is impossible to do it
(Ada AFAIK does), but it adds huge complexity (both for the
compiler and for the programmer who has to understand the
overloading rules - which can be quite complex even today),
and AFAIK was actively decided not to be done.
Note that you can get the desired effect by returning proxie
objects, and you can explicitly decide using the const method,
with help of the folowing template:
template<class T> inline T const& Const(T const& t) { return t; }
Then you can write:
int x=Const(a).foo();
and you will call foo() const for sure (and generate a compile
time error if no const version of foo() exists).
[...]
> Look at this example. Provided that std::string is implemented in a way
> that it can share data across different objects:
>
> string s1 = "Philip";
> cout << (void*) s1.c_str() << endl; // Address of "Philip"
> string s2 = s1;
> cout << (void*) s2.c_str() << endl; // Another string object, same address
> char c = s2[0]; // "Read" a character from s2
> cout << (void*) s2.c_str() << endl; // New address!
This is caused by the (IMHO unfortunate) desicion that
string::operator[] must return a true reference, not a proxy.
If it were allowed to return a proxy, then no unsharing would
be needed.
[...]
[ 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: James Kuyper <kuyper@wizard.net>
Date: 1999/02/09 Raw View
Gabriel Dos_Reis wrote:
>
> "Andrei Alexandrescu" <alexandrescua@micromodeling.com> writes:
>
> --------------------
> | I was thinking of it for a bit. Bjarne also used to say that ",," can be the
> | result of a typo.
> | What about using an explicit placeholder in there? Like:
> |
> | foo(!, !, 4);
> |
> | or
> |
> | foo(?, ?, 4);
> |
> | or the more verbose, but very suggestive:
> |
> | foo(default, default, 4);
> --------------------
>
> Very interesting... But then why not write out these arguements ?
Because you want the default behavior, while wanting to leave the
definition of the default behavior up to foo().
[ 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: sbnaran@localhost.localdomain.COM (Siemel Naran)
Date: 1999/02/09 Raw View
On 9 Feb 1999 04:06:43 GMT, Philip Koester <kozmik@okay.net> wrote:
>Siemel Naran wrote:
>>void foo2(const Object&); // declaration
>>void foo2(const Object& o) { } // definition
>>
>>void foo2(Object); // declaration
>>void foo2(const Object o) { } // definition
>
>This way of having the declaration differ from the definition is actually
>new to me. It's not part of the class's interface but adds some security
>for the implementation -- I do see a use for that. However, my foo()
>methods don't expect any arguments, and there is a reason for this. I will
>explain below.
It doesn't matter how many arguments foo(...) expects. When you
need to use the same object as a non-const and const object in the
same function, then this is a sign that you need to split your code
into two functions, one of which receives the object as a reference
to const, or as a const object.
>Look at this example. Provided that std::string is implemented in a way
>that it can share data across different objects:
>
>string s1 = "Philip";
>cout << (void*) s1.c_str() << endl; // Address of "Philip"
>string s2 = s1;
>cout << (void*) s2.c_str() << endl; // Another string object, same address
>char c = s2[0]; // "Read" a character from s2
>cout << (void*) s2.c_str() << endl; // New address!
>
>What happens here is by the time the operator [] is called, a new char
>buffer is allocated because the string class has no chance to predict if the
>returned char& is subject to reading or writing. Only declaring s2 by
>"const string s2 = s1;" solves this problem. As I already mentioned,
>programmers are likely to overlook this subtlety. However, as the return
>value of operator [] is *copied* to a char, I don't see a reason why the
>non-const flavor of that operator should be chosen here.
>
>I guess there is already a fair amount of code around that suffers from this
>problem.
What the function string::c_str() does is expose the underlying
implementation by returning a pointer to it. You've mentioned
one danger above. Here's another:
string s1="hello";
string s2="hello";
bool equal=(s1.c_str()==c2.c_str()); // answer is #false
See the book by John Lakos for a more thorough discussion.
The ideal solution is to remove the function c_str() from the
string class. But there are too many functions that accept C
style strings. So the next ideal solution is to avoid using the
c_str() function, or any function that taps in to the underlying
implementation, as a coding guideline. Lakos argues that this
leads to code that is more maintainable.
In any case, we may return from string::operator[] not a char&,
but rather a class string::reference. Then if we don't write to
the reference, we don't have to make a deep copy of the underlying
string (I guess you have a reference counting implementation in
mind). Ie, if we only use string::reference::operator char()
const, then it's as if the string were const, and we don't have to
change it.
But I don't think that the standard allows operator[] of any
conforming container to return a helper class; instead operator[]
must return a char& or T&. To me, the standard's definition of a
conforming container seems narrow. (BTW, in the conversion from
T1 to T2, two user-defined conversions should be allowed if one
of them is an operator conversion.)
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
[ 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 ]