How do you construct a long long
in gcc, similar to constructing an int
via int()
The following fails in gcc (4.6.3 20120306) (but passes on MSVC for example).
myFunctionCall(someValue, long long());
with error expected primary-expression before 'long'
(the column position indicates the first long is the location).
A simple change
myFunctionCall(someValue, (long long)int());
works fine - that is construct an int
and cast to long long
- indicating that gcc doesn't like the long long
ctor.
To summarize the brilliant explanation below from @birryree:
long long()
and it may not be standards compliantlong long
is equivalent to the literal 0LL
, so use myFunctionCall(someValue, 0LL)
typedef long_long_t long long
then long_long_t()
uint64_t
if you are after a type that is exactly 64 bits on any platform, rather than a type that is at least 64 bits, but may vary on different platforms.I wanted a definitive answer on what the expected behavior was, so I posted a question on comp.lang.c++.moderated
and got some great answers in return. So a thank you goes out to Johannes Schaub, Alf P. Steinbach (both from SO), and Francis Glassborrow for some information
This is not a bug in GCC - in fact it will break across multiple compilers - GCC 4.6, GCC 4.7, and Clang complain about similar errors like primary expression expected before '('
if you try this syntax:
long long x = long long();
Some primitives have spaces, and that is not allowed if you want to use the constructor-style initialization because of binding (long()
is bound, but long long()
has a free long
). Types with spaces in them (like long long
) can not use the type()
-construction form.
MSVC is more permissive here, though technically non-standard compliant (and it's not a language extension that you can disable).
There are alternatives for what you want to do:
Use 0LL
as your value in place of attempting long long()
- they would produce the same value.
This is how most code will be written too, so it will be most understandable to anyone else reading your code.
From your comments it seems like you really want long long
, so you can typedef
yourself to always guarantee you have a long long
type, like this:
int main() {
typedef long long MyLongLong;
long long x = MyLongLong(); // or MyLongLong x = MyLongLong();
}
Use a template to get around needing explicit naming:
template<typename TypeT>
struct Type { typedef TypeT T(); };
// call it like this:
long long ll = Type<long long>::T();
As I mentioned in my comments, you can use an aliased type, like int64_t
(from <cstdint>
), which across common platforms is a typedef long long int64_t
. This is a more platform dependent than the previous items in this list.
int64_t
is a fixed-width type that is 64-bits, which is typically how wide long long
is on platforms like linux-x86 and windows-x86. long long
is at least 64-bit wide, but can be longer. If your code will only run on certain platforms, or if you really need a fixed-width type, this might be a viable choice.
Thanks to the C++ newsgroup, I learned some additional ways of doing what you want to do, but unfortunately they're only in the realm of C++11 (and MSVC10 doesn't support either, and only very new compilers either way would):
The {}
way:
long long ll{}; // does the zero initialization
Using what Johannes refers to as the 'bord tools' in C++11 with std::common_type<T>
#include <type_traits>
int main() {
long long ll = std::common_type<long long>::type();
}
()
and initializing with 0
for POD types?You say this in a comment:
I don't think default ctor returns zero always - more typical behaviour is to leave memory untouched.
Well, for primitive types, that is not true at all.
From Section 8.5 of the ISO C++ Standard/2003 (don't have 2011, sorry, but this information didn't change too much):
To default-initialize an object of type
T
means:— if
T
is a non-POD class type (clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);— if
T
is an array type, each element is default-initialized;— otherwise, the object is zero-initialized.
The last clause is most important here because long long
, unsigned long
, int
, float
, etc. are all scalar/POD types, and so calling things like this:
int x = int();
Is exactly the same as doing this:
int x = 0;
Here is a more concrete example of what actually happens in code:
#include <iostream>
template<typename T>
void create_and_print() {
T y = T();
std::cout << y << std::endl;
}
int main() {
create_and_print<unsigned long long>();
typedef long long mll;
long long y = mll();
long long z = 0LL;
int mi = int();
}
Compile this with:
g++ -fdump-tree-original construction.cxx
And I get this in the generated tree dump:
;; Function int main() (null)
;; enabled by -tree-original
{
typedef mll mll;
long long int y = 0;
long long int z = 0;
int mi = 0;
<<cleanup_point <<< Unknown tree: expr_stmt
create_and_print<long long unsigned int> () >>>>>;
<<cleanup_point long long int y = 0;>>;
<<cleanup_point long long int z = 0;>>;
<<cleanup_point int mi = 0;>>;
}
return <retval> = 0;
;; Function void create_and_print() [with T = long long unsigned int] (null)
;; enabled by -tree-original
{
long long unsigned int y = 0;
<<cleanup_point long long unsigned int y = 0;>>;
<<cleanup_point <<< Unknown tree: expr_stmt
(void) std::basic_ostream<char>::operator<< ((struct __ostream_type *) std::basic_ostream<char>::operator<< (&cout, y), endl) >>>>>;
}
So from the code tree generated above, notice that all my variables are just being initialized with 0
, even if I use constructor-style default initialization, like with int mi = int()
. GCC will generate code that just does int mi = 0
.
My template function that just attempts to do default construction of some passed in typename T
, where T = unsigned long long
, also produced just a 0
-initialization code.
So in conclusion, if you want to default construct primitive types/PODs, it's like using 0
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With