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

Knowing which function to call

28 views
Skip to first unread message

Paul

unread,
Sep 15, 2018, 6:25:36 AM9/15/18
to
Using gcc, the below code prints 0 on the console.
Why does it decide that I mean the user-defined pow
rather than the pow defined in cmath?

(Note that cmath defines a version of pow that is
not in the std namespace. If I comment out the
user-defined pow, I get the obvious 16384.)

Many thanks for your help.

#include <cmath>
#include <iostream>

double pow(int x, int y)
{
return 0;
}

int main()
{
std::cout << pow(4, 7);
return 0;
}

Ian Collins

unread,
Sep 15, 2018, 6:38:21 AM9/15/18
to
On 15/09/18 22:25, Paul wrote:
> Using gcc, the below code prints 0 on the console.
> Why does it decide that I mean the user-defined pow
> rather than the pow defined in cmath?

Because you are passing two int parameters. If you change your call to
use doubles, you will match std::pow.

> (Note that cmath defines a version of pow that is
> not in the std namespace. If I comment out the
> user-defined pow, I get the obvious 16384.)

What's 16384?

> Many thanks for your help.
>
> #include <cmath>
> #include <iostream>
>
> double pow(int x, int y)
> {
> return 0;
> }
>
> int main()
> {
> std::cout << pow(4, 7);
> return 0;
> }

--
Ian.

Alf P. Steinbach

unread,
Sep 15, 2018, 6:39:44 AM9/15/18
to
On 15.09.2018 12:25, Paul wrote:
> Using gcc, the below code prints 0 on the console.
> Why does it decide that I mean the user-defined pow
> rather than the pow defined in cmath?

Your user-defined one, with `int` formal arguments, is a more specific
overload for the arguments used in the call.


> (Note that cmath defines a version of pow that is
> not in the std namespace.

With your compiler's implementation of the standard library `<cmath>`
defines the overloads of `pow` in the global namespace, but not
necessarily with some other compiler's implementation.

This is not portable code.


> If I comment out the user-defined pow, I get the obvious 16384.)

Or you can change the call to e.g. `pow( 4., 7)`.


> Many thanks for your help.
>
> #include <cmath>
> #include <iostream>
>
> double pow(int x, int y)
> {
> return 0;
> }
>
> int main()
> {
> std::cout << pow(4, 7);
> return 0;
> }

Mostly a cosmetics issue, but an explicit `return 0;` is redundant; it's
the default for `main`.

A side-issue: you can define an integer `pow` that's much faster than
the general `pow` for floating point numbers. The general idea is to use
repeated squaring via Horner's rule for calculating polynomials. OK that
description may sound as if it's very complicated; it's not.


Cheers & hth.,

- Alf

Ian Collins

unread,
Sep 15, 2018, 6:40:32 AM9/15/18
to
On 15/09/18 22:38, Ian Collins wrote:
> On 15/09/18 22:25, Paul wrote:
>> Using gcc, the below code prints 0 on the console.
>> Why does it decide that I mean the user-defined pow
>> rather than the pow defined in cmath?
>
> Because you are passing two int parameters. If you change your call to
> use doubles, you will match std::pow.
>
>> (Note that cmath defines a version of pow that is
>> not in the std namespace. If I comment out the
>> user-defined pow, I get the obvious 16384.)
>
> What's 16384?

The expected answer, ignore that comment!
--
Ian.

Ian Collins

unread,
Sep 15, 2018, 6:42:49 AM9/15/18
to
On 15/09/18 22:39, Alf P. Steinbach wrote:
> On 15.09.2018 12:25, Paul wrote:
>> Using gcc, the below code prints 0 on the console.
>> Why does it decide that I mean the user-defined pow
>> rather than the pow defined in cmath?
>
> Your user-defined one, with `int` formal arguments, is a more specific
> overload for the arguments used in the call.
>
>
>> (Note that cmath defines a version of pow that is
>> not in the std namespace.
>
> With your compiler's implementation of the standard library `<cmath>`
> defines the overloads of `pow` in the global namespace, but not
> necessarily with some other compiler's implementation.
>
> This is not portable code.
>
>
>> If I comment out the user-defined pow, I get the obvious 16384.)
>
> Or you can change the call to e.g. `pow( 4., 7)`.

That won't match either...

--
Ian.

David Brown

unread,
Sep 15, 2018, 7:12:06 AM9/15/18
to
Don't you know your 4-power's table? Back to the school bench with you,
boy!

Alf P. Steinbach

unread,
Sep 15, 2018, 7:31:01 AM9/15/18
to
On 15.09.2018 12:42, Ian Collins wrote:
> On 15/09/18 22:39, Alf P. Steinbach wrote:
>> [snip]
>> Or you can change the call to e.g. `pow( 4., 7)`.
>
> That won't match either...

Works for me. Why did you think it wouldn't match?


Cheers!,

- Alf

Paul

unread,
Sep 15, 2018, 7:52:28 AM9/15/18
to
I'm familiar with the implementation of pow you describe.
You go through a loop and do exponent >>= 1; base *= base at each
iteration until exponent reaches 0. if exponent is odd, then an extra
result *= base step is required.

Below code prints 0 with gcc. This surprises me because
it calls the user-defined version of pow in response to std::pow.
I'd expect it to print 16384.

#include <cmath>
#include <iostream>

double pow(double x, double y)
{
return 0;
}

int main()
{
std::cout << std::pow(4.0, 7.0);
}

Alf P. Steinbach

unread,
Sep 15, 2018, 8:11:06 AM9/15/18
to
On 15.09.2018 13:52, Paul wrote:
> [snip]
> Below code prints 0 with gcc. This surprises me because
> it calls the user-defined version of pow in response to std::pow.
> I'd expect it to print 16384.
>
> #include <cmath>
> #include <iostream>
>
> double pow(double x, double y)
> {
> return 0;
> }
>
> int main()
> {
> std::cout << std::pow(4.0, 7.0);
> }

Formally the explanation is that it's Undefined Behavior where anything
(including nothing) can happen, because

C++17 §20.5.4.3
<quote>
The C ++ standard library reserves the following kinds of names:

(1.1) macros
(1.2) global names
(1.3) names with external linkage

If a program declares or defines a name in a context where it is
reserved, other than as explicitly allowed by this Clause, its behavior
is undefined.
</quote>

From an in-practice view what happens is probably that the mechanism
that allows you to define overrides of e.g. `operator new`, kicks in
also for this (with your compiler) redefinition of a `pow` overload.

That was a nifty example, new to me. Thanks. :)


Cheers!,

- Alf

Paul

unread,
Sep 15, 2018, 8:35:23 AM9/15/18
to
I thought that the standard way of swapping was
using std::swap;
swap(a, b);

and that this means "Use the user-implemented version of swap
if it exists. Otherwise use std::swap".
So why isn't this undefined behaviour too? It seems very similar to my
code.

Paul

Paavo Helde

unread,
Sep 15, 2018, 10:20:00 AM9/15/18
to
std::swap is a template, which is only considered as a fallback in case
there is no ordinary function with an exactly matching signature.

pow(double, double) on the other hand is an ordinary function so
defining your own pow(double, double) may cause UB (depending on whether
<cmath> defines pow(double, double) in the global namespace or not,
which is unspecified).

So, what you have got is "unspecified UB" ;-)


Ben Bacarisse

unread,
Sep 15, 2018, 10:20:27 AM9/15/18
to
<snip>
> I thought that the standard way of swapping was
> using std::swap;
> swap(a, b);
>
> and that this means "Use the user-implemented version of swap
> if it exists. Otherwise use std::swap".
> So why isn't this undefined behaviour too? It seems very similar to my
> code.

The difference is that the header that defines std::swap does not also
define swap.

I still find your example curious because, though it is UB, a reason
often given for why the standard reserves names is so that it can assume
that the standard version is meant!

--
Ben.

Manfred

unread,
Sep 15, 2018, 10:41:30 AM9/15/18
to
On 9/15/2018 2:10 PM, Alf P. Steinbach wrote:
> On 15.09.2018 13:52, Paul wrote:
>> [snip]
>> Below code prints 0 with gcc.  This surprises me because
>> it calls the user-defined version of pow in response to std::pow.
>> I'd expect it to print 16384.
>>
>> #include <cmath>
>> #include <iostream>
>>
>> double pow(double x, double y)
>> {
>>      return 0;
>> }
>>
>> int main()
>> {
>>      std::cout << std::pow(4.0, 7.0);
>> }
>
> Formally the explanation is that it's Undefined Behavior where anything
> (including nothing) can happen, because
>
> C++17 §20.5.4.3
> <quote>
> The C ++ standard library reserves the following kinds of names:
>
> (1.1) macros
> (1.2) global names
> (1.3) names with external linkage
>
> If a program declares or defines a name in a context where it is
> reserved, other than as explicitly allowed by this Clause, its behavior
> is undefined.
> </quote>

I don't think it is undefined behavior, it is a matter of function
replacement instead (20.3.19 and 20.5.4.6).
The program creation process (5.2, p.9) specifies that library linkage
is performed last, so that all extern function definitions provided by
the program itself are used instead of the library supplied ones.

In the case of pow(), in glibc it is defined it in <math.h> in the
global namespace, and imported into std via 'using ::pow;" by <cmath>,
which explains why the one supplied by the program in the global
namespace overrides the library provided one even in namespace std.


>
> From an in-practice view what happens is probably that the mechanism
> that allows you to define overrides of e.g. `operator new`, kicks in
> also for this (with your compiler) redefinition of a `pow` overload.
This is in 20.5.4.6

Alf P. Steinbach

unread,
Sep 15, 2018, 10:48:02 AM9/15/18
to
A `using` declaration is formally a declaration, but the above `using`
declaration is not "in a context where [the name] is reserved", and
also, the /intent/ of the standard is clearly to prohibit user
redefinitions of names provided by the standard library, it's just a
less than perfect too inclusive wording when it's viewed as formalism.

The reserved context for `std::swap` is namespace `std`. There is no
global namespace counterpart. The global namespace counterpart for e.g.
`std::pow` is there for C compatibility, because `pow` was introduced in
C, and C has nothing like the C++ `std::swap`.

You know that a standard library header comes originally from C when
there is a <cFOO> or <FOO.h> variant of it.

---

So what happens if you put that `using` declaration in namespace `std`,
where the name is reserved?

In practice a compiler would have to be so called ¹"perverse" in order
to diagnose that, or to do anything ungood. It just affirms that the
name exists in this context, which it does. But formally the wording of
§20.5.4.3 is sufficiently unclear, using just the word "declares", that
I think it would be formally UB.

Then we're over in language lawyer territory. So called because like
some aspects of the law and religious texts it's mostly about getting
consensus (or usually, not!) about interpretations of subtle points that
do not really matter in practical programming. :)

---

I'm sorry that I didn't notice the UB in the very first example.

That's because it had an immediate and clear practical explanation, in
terms of overload resolution.


Cheers!,

- Alf

Notes:
¹ The notion of a "perverse" compiler also originated with C, as a way
to write maximally portable code, namely a compiler that would do its
utmost to detect UB and system dependencies and give formally permitted
but completely impractical results, but I've looked for the original
discussion for some time now and the articles seem to have disappeared.

Manfred

unread,
Sep 15, 2018, 10:54:52 AM9/15/18
to
Adding to what I wrote in another post (I don't think it is UB), the
section about reserved names says:
20.5.4.3.3 External linkage
...
p. 2
Each global function signature declared with external linkage in a
header is reserved to the implementation to designate that function
signature with external linkage.
...
p. 4
Each function signature from the C standard library declared with
external linkage is reserved to the implementation for use as a function
signature with both extern "C" and extern "C++" linkage...

Which I read as 'pow' being reserved as a 'function signature' with the
actual function definition subject to replacement by the program itself.
Do I understand it wrong?



>

Alf P. Steinbach

unread,
Sep 15, 2018, 11:00:56 AM9/15/18
to
Clearly `pow` is a global name in the standard library.

And that's regardless of whether it's declared as such by the included
headers.

And given that it's a global name in the standard library, the above
quoted paragraph says that it's UB to declare or define it in the global
namespace, a "context where it is reserved".


>, it is a matter of function
> replacement instead (20.3.19 and 20.5.4.6).

I agree that in practice it is apparently a matter of function
replacement, but the standard, via C++17 20.5.4.6 "Replacement
functions" that you refer to, only supports replacement of functions
from the `<new` header, such as the `operator new` allocation function.


> The program creation process (5.2, p.9) specifies that library linkage
> is performed last, so that all extern function definitions provided by
> the program itself are used instead of the library supplied ones.
>
> In the case of pow(), in glibc it is defined it in <math.h> in the
> global namespace, and imported into std via 'using ::pow;" by <cmath>,
> which explains why the one supplied by the program in the global
> namespace overrides the library provided one even in namespace std.

Yes, agreed, that's most probably what happens in practice.


>>  From an in-practice view what happens is probably that the mechanism
>> that allows you to define overrides of e.g. `operator new`, kicks in
>> also for this (with your compiler) redefinition of a `pow` overload.
> This is in 20.5.4.6

Yes, thanks.

Manfred

unread,
Sep 15, 2018, 11:30:19 AM9/15/18
to
The fact is that 20.5.4.3.3 (under 20.5.4.3 that you mention) says that
'pow' is "reserved to the implementation to designate that function
signature with external linkage"
So, the name 'pow' is reserved to designate a function /signature/.
It clearly forbids to define, say, a global variable named 'pow', it is
not that clear that it forbids a program-provided implementation of that
function, provided it keeps the same signature.

>
>
>> , it is a matter of function replacement instead (20.3.19 and 20.5.4.6).
>
> I agree that in practice it is apparently a matter of function
> replacement, but the standard, via C++17 20.5.4.6 "Replacement
> functions" that you refer to, only supports replacement of functions
> from the `<new` header, such as the `operator new` allocation function.
20.5.4.6 p.1 mentions "clauses from 21 through 33 and annex D", which
would suggest quite a broad scope.

Nonetheless, you are most probably right on UB due to 20.3.22 (involved
in the definition of replacement function 20.3.19) which defines a
"reserved function":
a function, specified as part of the C++ standard library, that must be
defined by the implementation [ Note: If a C++ program provides a
definition for any reserved function, the results are undefined. —end note ]

So, if pow() is a function that must be defined by the implementation,
replacing it results in UB.
This makes sense, since other standard library functions may rely on
(possibly implementation-defined) properties of pow() that, if replaced,
may break the behavior of such other functions.

Ian Collins

unread,
Sep 15, 2018, 6:08:21 PM9/15/18
to
I should have said an ambiguous match. Double checked with g++ and clang++:

x.cc: In function ‘int main()’:
x.cc:11:27: error: call of overloaded ‘pow(double, int)’ is ambiguous
std::cout << pow(4., 7) << '\n';

--
Ian.

Alf P. Steinbach

unread,
Sep 15, 2018, 10:23:10 PM9/15/18
to
Thanks.

I only tested with the fixed (portable) code, using <math.h> instead of
<cmath>. With that, argument `4.` worked with both g++ and Visual C++.

Using <math.h> should ideally not have made any difference: either it
should compile or not, I thought.

But as it turns out, when you include <math.h>, or include <cmath> with
a `using std::pow`, with g++ you get an additional overload

template< class _Tp, class _Up >
auto pow( _Tp, _Up )
-> constexpr typename __gnu_cxx::__promote_2<_Tp, _Up>::__type;

and with Visual C++ there is anyway an overload

auto pow( double, int ) -> double;

I found these overloads simply by compiling a call `pow( "Blah", 2 )`.

In C++17 the wording that mandates such overloads, without detailing
exactly what they should be, is §2.9.1/2:


<quote>
For each set of overloaded functions within <cmath> , with the exception
of `abs`, there shall be additional overloads sufficient to ensure:

1. If any argument of arithmetic type corresponding to a double
parameter has type long double , then all arguments of arithmetic type
(6.9.1) corresponding to double parameters are effectively cast to long
double.

2. Otherwise, if any argument of arithmetic type corresponding to a
double parameter has type double or an integer type, then all arguments
of arithmetic type corresponding to double parameters are effectively
cast to double.

3. Otherwise, all arguments of arithmetic type corresponding to double
parameters have type float.

[Note: `abs` is exempted from these rules in order to stay compatible
with C. —end note ]
</quote>


So that's the technical: when `<math.h>` is included, or alternatively
when one includes `<cmath>` with a `using std::pow;` or `using namespace
std;`, then the expression `pow( 4., 7 )` is well-defined, unambiguous.

However, I hadn't thought this through. I could just as well have turned
out wrong. So, thanks, that was a learning experience. :)


Cheers!,

- Alf

Alf P. Steinbach

unread,
Sep 15, 2018, 10:25:32 PM9/15/18
to
On 16.09.2018 04:22, Alf P. Steinbach wrote:
>
> In C++17 the wording that mandates such overloads, without detailing
> exactly what they should be, is §2.9.1/2:

Oops, §29.9.1/2.

Cheers!,

- Alf

0 new messages