Discussion:
int32_t vs. int64_t vs. long: Ambiguous
(too old to reply)
Juha Nieminen
2015-05-04 08:00:52 UTC
Permalink
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: ***@netfront.net ---
Luca Risolia
2015-05-04 09:12:54 UTC
Permalink
Post by Juha Nieminen
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?
Post by Juha Nieminen
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
2015-05-04 09:41:03 UTC
Permalink
Overloading is inherently problematic, it is unavoidable.
Have one function with intmax_t type parameter.
Post by Juha Nieminen
//--------------------------------------------------------------------
#include<cstdint>
#include<iostream>
void foo(std::int32_t) { std::cout<< "int32_t\n"; }
void foo(std::int64_t) { std::cout<< "int64_t\n"; }
Jorgen Grahn
2015-05-04 22:04:56 UTC
Permalink
Post by Lőrinczy Zsigmond
Post by Juha Nieminen
//--------------------------------------------------------------------
#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 .
legalize+ (Richard)
2015-05-04 17:24:35 UTC
Permalink
[Please do not mail me a copy of your followup]
Post by Juha Nieminen
//--------------------------------------------------------------------
#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
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>
Vir Campestris
2015-05-04 20:06:19 UTC
Permalink
Post by legalize+ (Richard)
[Please do not mail me a copy of your followup]
Post by Juha Nieminen
//--------------------------------------------------------------------
#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
test.cc:8:14: error: call to 'foo' is ambiguous
assert(sizeof(123L) == sizeof(std::int64_t));
From the error, I'm guessing this will fail.
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,
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
legalize+ (Richard)
2015-05-05 14:58:14 UTC
Permalink
[Please do not mail me a copy of your followup]
Post by Vir Campestris
Post by legalize+ (Richard)
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.
Post by Vir Campestris
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
--
"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
2015-05-04 19:26:40 UTC
Permalink
Post by Juha Nieminen
//--------------------------------------------------------------------
#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
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.
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
void foo(long long) { std::cout << "long long\n"; }
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.
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
Paavo Helde
2015-05-04 20:46:57 UTC
Permalink
Post by Juha Nieminen
//--------------------------------------------------------------------
#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
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.
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
void foo(long long) { std::cout << "long long\n"; }
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
Juha Nieminen
2015-05-05 10:18:17 UTC
Permalink
Post by Paavo Helde
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.

--- news://freenews.netfront.net/ - complaints: ***@netfront.net ---
Loading...