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

int32_t vs. int64_t vs. long: Ambiguous

48 views
Skip to first unread message

Juha Nieminen

unread,
May 4, 2015, 4:01:01 AM5/4/15
to
Consider this program:

//--------------------------------------------------------------------
#include <cstdint>
#include <iostream>

void foo(std::int32_t) { std::cout << "int32_t\n"; }
void foo(std::int64_t) { std::cout << "int64_t\n"; }

int main() { foo(123L); }
//--------------------------------------------------------------------

If I try to compile it with clang++ (in C++11 mode), on a 64-bit target
it gives me:

test.cc:8:14: error: call to 'foo' is ambiguous

I do not understand why exactly it's doing that. Why would it be
ambiguous? (Given that a long type is 64-bit on this target, it would
quite unambiguously not fit into a std::int32_t, so why does it
consider it a valid match?) Note that if I call foo(123) it does not
give any error.

The problem can be solved by adding this version:

void foo(long) { std::cout << "long\n"; }

The thing is, I don't believe this to be portable anymore. If for
example std::int64_t happens to be defined as 'long' in some other
compiler, it would give an error. Indeed, if I did this:

void foo(long long) { std::cout << "long long\n"; }

it gives me:

test.cc:7:6: error: redefinition of 'foo'

And yes, I need to use std::int32_t & co because this is rather low-level
binary code manipulation which needs to handle exact bit sizes.

--- news://freenews.netfront.net/ - complaints: ne...@netfront.net ---

Luca Risolia

unread,
May 4, 2015, 5:13:34 AM5/4/15
to
On 04/05/2015 10:00, Juha Nieminen wrote:
> void foo(std::int32_t) { std::cout << "int32_t\n"; }
> void foo(std::int64_t) { std::cout << "int64_t\n"; }
>
> int main() { foo(123L); }

> test.cc:8:14: error: call to 'foo' is ambiguous
>
> I do not understand why exactly it's doing that. Why would it be
> ambiguous? (Given that a long type is 64-bit on this target, it would
> quite unambiguously not fit into a std::int32_t, so why does it
> consider it a valid match?)

long is 64-bit, ok, but are you sure std::int64_t is defined as long in
your implementation?

> The problem can be solved by adding this version:
>
> void foo(long) { std::cout << "long\n"; }
>
> The thing is, I don't believe this to be portable anymore.

If you care about portability, consider that fixed width integers types
are optional for a conforming C++ implementation.

Lőrinczy Zsigmond

unread,
May 4, 2015, 5:41:23 AM5/4/15
to
Overloading is inherently problematic, it is unavoidable.
Have one function with intmax_t type parameter.

Richard

unread,
May 4, 2015, 1:24:45 PM5/4/15
to
[Please do not mail me a copy of your followup]

Juha Nieminen <nos...@thanks.invalid> spake the secret code
<mi78vh$2i9c$1...@adenine.netfront.net> thusly:

>Consider this program:
>
>//--------------------------------------------------------------------
>#include <cstdint>
>#include <iostream>
>
>void foo(std::int32_t) { std::cout << "int32_t\n"; }
>void foo(std::int64_t) { std::cout << "int64_t\n"; }
>
>int main() { foo(123L); }
>//--------------------------------------------------------------------
>
>If I try to compile it with clang++ (in C++11 mode), on a 64-bit target
>it gives me:
>
>test.cc:8:14: error: call to 'foo' is ambiguous

Try this:

assert(sizeof(123L) == sizeof(std::int64_t));

From the error, I'm guessing this will fail.

Then try:

assert(sizeof(123LL) == sizeof(std::int64_t));

and that will most likely succeed.

If it does, then use long long's constants for 64-bit integers,
alternatively you can explicitly select the overload by doing:

foo(static_cast<std::int64_t>(123));

--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

Mr Flibble

unread,
May 4, 2015, 3:26:52 PM5/4/15
to
You shouldn't be mixing 'long' with the sized integer typedefs in fact
you shouldn't be using 'long' (or even 'int') at all: always use the
sized integer typedefs.

/Flibble

Vir Campestris

unread,
May 4, 2015, 4:06:28 PM5/4/15
to
On 04/05/2015 18:24, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Juha Nieminen <nos...@thanks.invalid> spake the secret code
> <mi78vh$2i9c$1...@adenine.netfront.net> thusly:
>
>> Consider this program:
>>
>> //--------------------------------------------------------------------
>> #include <cstdint>
>> #include <iostream>
>>
>> void foo(std::int32_t) { std::cout << "int32_t\n"; }
>> void foo(std::int64_t) { std::cout << "int64_t\n"; }
>>
>> int main() { foo(123L); }
>> //--------------------------------------------------------------------
>>
>> If I try to compile it with clang++ (in C++11 mode), on a 64-bit target
>> it gives me:
>>
>> test.cc:8:14: error: call to 'foo' is ambiguous
>
> Try this:
>
> assert(sizeof(123L) == sizeof(std::int64_t));
>
> From the error, I'm guessing this will fail.
>
> Then try:
>
> assert(sizeof(123LL) == sizeof(std::int64_t));
>
> and that will most likely succeed.
>
> If it does, then use long long's constants for 64-bit integers,
> alternatively you can explicitly select the overload by doing:
>
> foo(static_cast<std::int64_t>(123));
>

I don't see why this would make it compile OK giving it 123, but not
123L. (you snipped "Note that if I call foo(123) it does not
give any error.")

Andy

Paavo Helde

unread,
May 4, 2015, 4:47:14 PM5/4/15
to
Juha Nieminen <nos...@thanks.invalid> wrote in news:mi78vh$2i9c$1
@adenine.netfront.net:

> Consider this program:
>
> //--------------------------------------------------------------------
> #include <cstdint>
> #include <iostream>
>
> void foo(std::int32_t) { std::cout << "int32_t\n"; }
> void foo(std::int64_t) { std::cout << "int64_t\n"; }
>
> int main() { foo(123L); }
> //--------------------------------------------------------------------
>
> If I try to compile it with clang++ (in C++11 mode), on a 64-bit target
> it gives me:
>
> test.cc:8:14: error: call to 'foo' is ambiguous
>
> I do not understand why exactly it's doing that. Why would it be
> ambiguous? (Given that a long type is 64-bit on this target, it would
> quite unambiguously not fit into a std::int32_t, so why does it
> consider it a valid match?) Note that if I call foo(123) it does not
> give any error.
>
> The problem can be solved by adding this version:
>
> void foo(long) { std::cout << "long\n"; }
>
> The thing is, I don't believe this to be portable anymore. If for
> example std::int64_t happens to be defined as 'long' in some other
> compiler, it would give an error. Indeed, if I did this:
>
> void foo(long long) { std::cout << "long long\n"; }
>
> it gives me:
>
> test.cc:7:6: error: redefinition of 'foo'

This clearly shows that your implementation has typedeffed int64_t as
long long, not as long. The standard says int64_t must be a typedef, but
does not say of which type. And it cannot be a typedef of long and long
long at the same time - these are required to be different types.

Cheers
Paavo

Jorgen Grahn

unread,
May 4, 2015, 6:05:11 PM5/4/15
to
On Mon, 2015-05-04, L?rinczy Zsigmond wrote:
> On 2015-05-04 10:00, Juha Nieminen wrote:
>> Consider this program:
>>
>> //--------------------------------------------------------------------
>> #include<cstdint>
>> #include<iostream>
>>
>> void foo(std::int32_t) { std::cout<< "int32_t\n"; }
>> void foo(std::int64_t) { std::cout<< "int64_t\n"; }

> Overloading is inherently problematic, it is unavoidable.
> Have one function with intmax_t type parameter.

It's problematic with the builtin types and all their implicit
conversions (like here), but not in general.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Juha Nieminen

unread,
May 5, 2015, 6:18:35 AM5/5/15
to
Paavo Helde <myfir...@osa.pri.ee> wrote:
> This clearly shows that your implementation has typedeffed int64_t as
> long long, not as long. The standard says int64_t must be a typedef, but
> does not say of which type. And it cannot be a typedef of long and long
> long at the same time - these are required to be different types.

That doesn't really explain why foo(short(123)) compiles just fine
even though neither version of the function is an exact match, and
either one could be a valid match. Clearly short is a distinct type
from int32_t and int64_t (yet it matches int32_t unambiguously).

I don't understand why a 64-bit long can't match int64_t given that
they are identical in size and signedness.

Richard

unread,
May 5, 2015, 10:58:23 AM5/5/15
to
[Please do not mail me a copy of your followup]

Vir Campestris <vir.cam...@invalid.invalid> spake the secret code
<FaSdnd9ydJOnTNrI...@brightview.co.uk> thusly:

>> foo(static_cast<std::int64_t>(123));
>>
>
>I don't see why this would make it compile OK giving it 123,

123 is the argument to static_cast<> which explicitly promotes the
integral constant 123 to the type std::int64_t and the overload for
that type is selected.

>but not
>123L. (you snipped "Note that if I call foo(123) it does not
>give any error.")

123 is an integer literal with no type suffix. An integer literal
with no type suffix tells the compiler to pick the smallest type that
can hold the literal. For a decimal literal with no suffix, the type
chosen is the first of int, long int, or long long int that can hold
the value[1]. In your case, this is int. std::int32_t on your
implementation is apparently a typedef for int. So calling foo(123)
does work, but it doesn't call the 64-bit overload.

[1] See section 2.14.2 Integer Literals in the standard
0 new messages