Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Function declaration default to another param's value

63 views
Skip to first unread message

Rick C. Hodgin

unread,
Jun 6, 2016, 8:53:40 AM6/6/16
to
I was trying to do this today, and it's not allowed in Microsoft's C++
compiler:

// In header file
int myfunc(int val1, int val2 = val1);

// In source file
int myfunc(int val1, int val2)
{
// Code goes here
}

Is it allowed? And if not, why not? The value would be known at compile-
time and could be easily populated.

Best regards,
Rick C. Hodgin

Ben Bacarisse

unread,
Jun 6, 2016, 9:13:18 AM6/6/16
to
"Rick C. Hodgin" <rick.c...@gmail.com> writes:

> I was trying to do this today, and it's not allowed in Microsoft's C++
> compiler:
>
> // In header file
> int myfunc(int val1, int val2 = val1);
>
> // In source file
> int myfunc(int val1, int val2)
> {
> // Code goes here
> }
>
> Is it allowed?

Yes, it's allowed. What is the error message?

<snip>
--
Ben.

Rick C. Hodgin

unread,
Jun 6, 2016, 9:19:48 AM6/6/16
to
In VS2010 (100 toolset):

"error C2587: 'val1' : illegal use of local variable as default parameter."

In VS2015 (140 toolset):

"error C2587: 'val1' : illegal use of local variable as default parameter."

Alain Ketterlin

unread,
Jun 6, 2016, 9:25:10 AM6/6/16
to
Ben Bacarisse <ben.u...@bsb.me.uk> writes:

>> // In header file
>> int myfunc(int val1, int val2 = val1);
>>
>> // In source file
>> int myfunc(int val1, int val2)
>> {
>> // Code goes here
>> }
>>
>> Is it allowed?
>
> Yes, it's allowed. What is the error message?

It's not allowed. From N4296, §8.3.6p9:

| A default argument is evaluated each time the function is called with
| no argument for the corresponding parameter. The order of evaluation
| of function arguments is unspecified. Consequently, parameters of a
| function shall not be used in a default argument, even if they are not
| evaluated. Parameters of a function declared before a default argument
| are in scope and can hide namespace and class member names. [ Example:
|
| int a;
| int f(int a, int b = a);
| // error: parameter a
| // used as default argument
| [...]]

-- Alain.

Ben Bacarisse

unread,
Jun 6, 2016, 9:26:52 AM6/6/16
to
"Rick C. Hodgin" <rick.c...@gmail.com> writes:

> On Monday, June 6, 2016 at 9:13:18 AM UTC-4, Ben Bacarisse wrote:
>> "Rick C. Hodgin" <rick.c...@gmail.com> writes:
>>
>> > I was trying to do this today, and it's not allowed in Microsoft's C++
>> > compiler:
>> >
>> > // In header file
>> > int myfunc(int val1, int val2 = val1);
>> >
>> > // In source file
>> > int myfunc(int val1, int val2)
>> > {
>> > // Code goes here
>> > }
>> >
>> > Is it allowed?
>>
>> Yes, it's allowed. What is the error message?
>
> In VS2010 (100 toolset):
>
> "error C2587: 'val1' : illegal use of local variable as default
> parameter."

Ah, I did not spot that val1 was a previous argument. No, that is not
allowed. From 8.3.6 p9:

"Default arguments are evaluated each time the function is called. The
order of evaluation of function arguments is unspecified. Consequently,
parameters of a function shall not be used in a default argument, even
if they are not evaluated."

<snip>
--
Ben.

Ben Bacarisse

unread,
Jun 6, 2016, 9:28:03 AM6/6/16
to
Ben Bacarisse <ben.u...@bsb.me.uk> writes:

> "Rick C. Hodgin" <rick.c...@gmail.com> writes:
>
>> I was trying to do this today, and it's not allowed in Microsoft's C++
>> compiler:
>>
>> // In header file
>> int myfunc(int val1, int val2 = val1);
>>
>> // In source file
>> int myfunc(int val1, int val2)
>> {
>> // Code goes here
>> }
>>
>> Is it allowed?
>
> Yes, it's allowed.

I need to correct myself to keep the record straight. It's not
allowed. I did not spot the fact that val1 is a previous argument.

--
Ben.

Martin Shobe

unread,
Jun 6, 2016, 9:28:57 AM6/6/16
to
Really? I thought that function parameters could only be used if they
were unevaluated (and before c++14, not at all). Have I missed something?

Martin Shobe

Alf P. Steinbach

unread,
Jun 6, 2016, 9:42:06 AM6/6/16
to
On 06.06.2016 14:53, Rick C. Hodgin wrote:
> I was trying to do this today, and it's not allowed in Microsoft's C++
> compiler:
>
> // In header file
> int myfunc(int val1, int val2 = val1);
>
> // In source file
> int myfunc(int val1, int val2)
> {
> // Code goes here
> }
>
> Is it allowed?

Nope.


> And if not, why not?

I am not sure, except that the default argument value mechanism on the
whole gives the impression of being an ad-hoc feature.

The standard mumbles something about unspecified order of argument
initialization, but if the above was supported it would simply impose a
constraint on the order of argument initialization for calls using the
default(s).

Evidence of ad-hoc nature of the feature: you can move the "= something"
from the header file declaration to the implementation, and as far as
the rules of C++ are concerned that's OK. But then in general the
compiler can't see the "= something" when it compiles a call to the
function from another TU. And hence the default would be of no general
value, it would not be usable outside the implementation file.

Worse, in my opinion: in a class you can't do e.g.

struct S
{
int x;
void foo( int t = x ) {} //! Nyet.
};

Which surely has nothing to do with argument initialization order.

It's not difficult to work around that, to do the compiler's job for it,
so to speak, but why oh why is it that way?

I have no good explanation, other than that the feature seems ad hoc.


> The value would be known at compile-time and could be easily populated.

Yes.


Cheers, and sorry that this can't be much help!,

- Alf

Bo Persson

unread,
Jun 6, 2016, 10:57:26 AM6/6/16
to
However, an easy workaround is to add an overload

inline int myfunc(int val1)
{ return myfunc(val1, val1); }



Bo Persson

Rick C. Hodgin

unread,
Jun 7, 2016, 8:45:44 AM6/7/16
to
It's all good. :-)

Personally, I think it's a missing feature, and I'm surprised someone of
influence in the C++ standards group hasn't already wanted this ability
by now. But, as Bo Persson points out, an easy work-around. That's
probably why.

I think this is also a missing feature:

// In header
int myfunc(int a, int b = local_b);

// In body
int myfunc(int a, int b)
{
return(a + b);
}

// Where referenced in source code
int elsewhere(void)
{
int local_b = 5;

return(myfunc(1));
}

I think the ability should exist for parameter defaults to be able to
reference things that are in scope locally or globally.

Best regards,
Rick C. Hodign

David Brown

unread,
Jun 7, 2016, 9:55:49 AM6/7/16
to
On 07/06/16 14:45, Rick C. Hodgin wrote:
> On Monday, June 6, 2016 at 9:42:06 AM UTC-4, Alf P. Steinbach wrote:
>> On 06.06.2016 14:53, Rick C. Hodgin wrote:
>>> I was trying to do this today, and it's not allowed in Microsoft's C++
>>> compiler:
>>>
>>> // In header file
>>> int myfunc(int val1, int val2 = val1);
>>>
>>> // In source file
>>> int myfunc(int val1, int val2)
>>> {
>>> // Code goes here
>>> }
>>>
>>> Is it allowed?
>>
>> Nope.
>>

What would be the use-cases of such a default parameter? I could think
of a few occasions, but none that would be common enough to make it
worth adding to the standard. And rather having the default of "val2"
being simply the same as "val1", I think there would be more useful
cases for the default of "val2" being an expression in "val1". But that
would quickly get difficult to specify well - and I think Bo Persson's
neat workaround makes complicated defaults unnecessary. Rather than
writing:

void sendString(const char* p, int len = strlen(p));

you just write:

void sendString(const char* p, int len);
inline void sendString(const char* p) {
sendString(p, strlen(p);
}


>>
>> Worse, in my opinion: in a class you can't do e.g.
>>
>> struct S
>> {
>> int x;
>> void foo( int t = x ) {} //! Nyet.
>> };
>>

That could be neat. But again, it can be handled by the easy workaround.

On the other hand, given that there /is/ an easy workaround, then it
should not be too difficult to implement the syntax you want.

>
> It's all good. :-)
>
> Personally, I think it's a missing feature, and I'm surprised someone of
> influence in the C++ standards group hasn't already wanted this ability
> by now. But, as Bo Persson points out, an easy work-around. That's
> probably why.
>
> I think this is also a missing feature:
>
> // In header
> int myfunc(int a, int b = local_b);
>
> // In body
> int myfunc(int a, int b)
> {
> return(a + b);
> }
>
> // Where referenced in source code
> int elsewhere(void)
> {
> int local_b = 5;
>
> return(myfunc(1));
> }
>
> I think the ability should exist for parameter defaults to be able to
> reference things that are in scope locally or globally.
>

This would make the header file depend on variables declared in the
source file that uses the header - that's going to open a /huge/ can of
worms.

In C++, you can currently write:

#include <functional>
using std::bind;
using namespace std::placeholders;

int elsewhere(void) {
int local_b = 5;

auto org_myfunc = myfunc;
auto myfunc = bind(org_myfunc, _1, local_b);

return myfunc(1);
}

or, using lambdas,

int elsewhere(void) {
int local_b = 5;

auto org_myfunc = myfunc;
auto myfunc = [local_b, org_myfunc](int a)
{ return org_myfunc(a, local_b); };

return myfunc(1);
}

or, using classes,

class Fmyfunc {
private :
int def_b;
public :
Fmyfunc(int default_b = 0) : def_b(default_b) {};
int operator()(int a, int b) { return myfunc(a, b); };
int operator()(int a) { return (*this)(a, def_b); };
void setDefault(int default_b = 0) { def_b = default_b; };
};

int elsewhere(void) {
int local_b = 5;

auto myfunc = Fmyfunc(local_b);

return myfunc(1);
}

You can also use templates in creative ways here.

(In each of these cases, gcc has no problem generating optimal code, so
there is no run-time overhead.)

In other words, you can make your own local version of "myfunc" which
has local modifications (such as a different default). This puts the
control of the local modifications where it should be, where it is used
- and leaves the definition and implementation of myfunc unaware of the
local modifications.

The challenge for your language is to come up with a neater syntax for
doing this! An obvious improvement would be to allow:

auto myfunc = bind(myfunc, _1, local_b);

instead of

auto org_myfunc = myfunc;
auto myfunc = bind(org_myfunc, _1, local_b);


A key point here is to allow functions to be manipulated directly, or
nearly directly - if functions are first-class objects, all sorts of
tricks are possible.


Paavo Helde

unread,
Jun 7, 2016, 5:36:04 PM6/7/16
to
On 7.06.2016 15:45, Rick C. Hodgin wrote:
> I think this is also a missing feature:
>
> // In header
> int myfunc(int a, int b = local_b);
>
> // In body
> int myfunc(int a, int b)
> {
> return(a + b);
> }
>
> // Where referenced in source code
> int elsewhere(void)
> {
> int local_b = 5;
>
> return(myfunc(1));
> }
>
> I think the ability should exist for parameter defaults to be able to
> reference things that are in scope locally or globally.

This would be too magic/transparent. In source code, a local variable
local_b is created, but one could not check by textual search if and
where it is used. That would be a major no-no.

(Been there, done that. Believe me, it's not a good idea).

Cheers
Paavo


BartC

unread,
Jun 7, 2016, 5:50:34 PM6/7/16
to
On 07/06/2016 13:45, Rick C. Hodgin wrote:

> I think this is also a missing feature:
>
> // In header
> int myfunc(int a, int b = local_b);
>
> // In body
> int myfunc(int a, int b)
> {
> return(a + b);
> }
>
> // Where referenced in source code
> int elsewhere(void)
> {
> int local_b = 5;
>
> return(myfunc(1));
> }

(1) When a default expression is used for a parameter, should it
look:

(a) around the header declaration to resolve the names encountered
in the expression?

(b) around the definition of the function (which will usually not be
visible at the call-site)?

(c) at the call-site?

(2) In your above example, presumably you want formal parameter 'b' in
myfunc() to be set to local_b from the call-site. But what happens
when myfunc() is called from anywhere else?

(I can't anyway see how it can work when writing a library function,
and you use a default name that exists in a caller's module; how do
you know what's in the caller's code?)

(3) (I understood that in C at least, the names chosen for parameters in
declarations were arbitrary, so this would be a problem for the
example in your OP (as changing parameter names could change the
behaviour if it means a different name coming into scope for the
default expression).)

--
Bartc

Rick C. Hodgin

unread,
Jun 7, 2016, 5:51:23 PM6/7/16
to
Paavo Helde wrote:
> (Been there, done that. Believe me, it's not a good idea).

I'm not prepared to make that decision for all developers everywhere
at all times and in all cases.

https://groups.google.com/forum/!topic/caliveprogramminglanguage/DY-RAJ7zaM8

Rick C. Hodgin

unread,
Jun 7, 2016, 5:57:24 PM6/7/16
to
Oops! Mobile screen jumped and I hit "Post"!

Paavo Helde wrote:
> (Been there, done that. Believe me, it's not a good idea).

I'm not prepared to make that decision for all developers everywhere at all times and in all cases.

https://groups.google.com/forum/?nomobile=true#!topic/caliveprogramminglanguage/DY-RAJ7zaM8

I can think of times I could use it.

Paavo Helde

unread,
Jun 7, 2016, 6:06:57 PM6/7/16
to
On 8.06.2016 0:51, Rick C. Hodgin wrote:
> Paavo Helde wrote:
>> (Been there, done that. Believe me, it's not a good idea).
>
> I'm not prepared to make that decision for all developers everywhere
> at all times and in all cases.

Well, I am, at least for C++ developers. Making use of such a feature
would effectively turn the language into a write-only language, similar
to Perl or advanced regex. This might be OK for some quick prototyping
languages, but this is not the niche of C++.

Cheers
Paavo


Rick C. Hodgin

unread,
Jun 7, 2016, 6:08:21 PM6/7/16
to
Bart Mancuso spoke:
> " 'Central Intelligence Agency' ... now there's a contradiction in terms."

Bartc wrote:
> [paraphrased] "Where should it look?"

(1) Other parameters.
(2) Scoped variables.
(3) Local variables.
(4) Global variables.
(5) Solar variables.
(6) Galactic variables.
(7) Universal variables.
(8) If on a Windows machine, the registry.
(9) If on a computer with a recycle bin, the recycle bin.
(10) Popup a console and ask, and don't take "no" for an answer
(unless the variable name is "no," of course).
(11) If they pressed Ctrl+C, use Google.

:-D

David Brown

unread,
Jun 8, 2016, 2:58:15 AM6/8/16
to
On 07/06/16 23:50, BartC wrote:

> (3) (I understood that in C at least, the names chosen for parameters in
> declarations were arbitrary, so this would be a problem for the
> example in your OP (as changing parameter names could change the
> behaviour if it means a different name coming into scope for the
> default expression).)
>

This is actually one of the few things that I would change in C and C++.
Plenty of people disagree with me on this one (in addition to the
"don't break existing code" argument). But I would be happier with a
rule that all definitions and declarations of the same function must use
the same names for parameters (and declarations could not omit names).
As well as being more consistent and closer to self-documenting code, it
would make it possible to use named parameter function calls (i.e.,
"myfunc(.b = 3, .a = 1);" or similar syntax).

IMHO, the prime goal for new language should not be to make it easy to
write code, or easy to be flexible - it should make it easy to write
/correct/ programs and /hard/ to write incorrect ones. That means more
effort on the part of the programmer in some aspects, but savings in the
long run. Apparent short-cuts, like making the default parameter value
come from anywhere around the universe, would make some tasks appear
quick and easy, but lead to longer debugging, harder maintenance, and
reduced code re-use. On the other hand, although using full parameter
names in header declaration means a little more typing, it saves time
overall.


0 new messages