我想要一个关于预期行为的明确答案,所以我发布了一个问题comp.lang.c++.moderated
并得到了一些很好的答案作为回报。 感谢 Johannes Schaub、Alf P. Steinbach(均来自 SO)和 Francis Glassborrow 提供一些信息
这不是 GCC 中的错误 - 实际上它会跨越多个编译器 - GCC 4.6、GCC 4.7 和 Clang 会抱怨类似的错误,例如primary expression expected before '('
尝试以下语法:
long long x = long long();
一些原语有空格,如果你想使用构造函数风格的初始化,这是不允许的,因为绑定(long()
是绑定的,但long long()
有一个免费的long
)。带有空格的类型(如long long
)不能使用type()
-construction 形式。
MSVC 在这里更宽松,尽管在技术上不符合标准(而且它不是您可以禁用的语言扩展)。
解决方案/解决方法
您想要做的事情有其他选择:
用作0LL
您的价值而不是尝试long long()
-它们会产生相同的价值。
这也是大多数代码的编写方式,因此其他阅读您的代码的人最容易理解。
从你的评论看来你真的想要long long
,所以你可以typedef
自己保证你有一个long long
类型,像这样:
int main() {
typedef long long MyLongLong;
long long x = MyLongLong(); // or MyLongLong x = MyLongLong();
}
使用模板来解决需要显式命名的问题:
template<typename TypeT>
struct Type { typedef TypeT T(); };
// call it like this:
long long ll = Type<long long>::T();
正如我在评论中提到的,您可以使用别名类型,例如int64_t
(from <cstdint>
),它在通用平台上是typedef long long int64_t
. 这比此列表中的前面的项目更依赖于平台。
int64_t
是 64 位的固定宽度类型,通常long long
是 linux-x86 和 windows-x86 等平台上的宽度。long long
至少 64 位宽,但可以更长。如果您的代码只能在某些平台上运行,或者您确实需要固定宽度的类型,那么这可能是一个可行的选择。
C++11 解决方案
感谢 C++ 新闻组,我学到了一些额外的方法来做你想做的事,但不幸的是,它们只在 C++11 的领域内(而且 MSVC10 也不支持,而且只有非常新的编译器会):
{}
方式:
long long ll{}; // does the zero initialization
在 C++11 中使用 Johannes 所说的“边框工具”std::common_type<T>
#include <type_traits>
int main() {
long long ll = std::common_type<long long>::type();
}
那么POD 类型()
和初始化之间有真正的区别吗?0
你在评论中这样说:
我不认为默认 ctor 总是返回零 - 更典型的行为是保持内存不变。
好吧,对于原始类型,这根本不是真的。
来自ISO C++ Standard/2003的第 8.5 节(没有 2011,抱歉,但此信息没有太大变化):
默认初始化类型的对象T
意味着:
— 如果T
是非 POD 类类型(第 9 条),则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数,则初始化是非良构的);
— 如果T
是数组类型,则每个元素都是默认初始化的;
—否则,对象被零初始化。
最后一个子句在这里最重要,因为long long
, unsigned long
, int
,float
等都是标量/POD 类型,因此调用如下:
int x = int();
与这样做完全相同:
int x = 0;
生成的代码示例
这是代码中实际发生的更具体的示例:
#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();
}
编译:
g++ -fdump-tree-original construction.cxx
我在生成的树转储中得到了这个:
;; 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) >>>>>;
}
生成的代码含义
因此,从上面生成的代码树中,请注意我的所有变量都只是用 初始化0
,即使我使用构造函数样式的默认初始化,例如 with int mi = int()
。GCC 将生成刚刚执行的代码int mi = 0
。
我的模板函数只是尝试对一些传入的typename T
, where进行默认构造T = unsigned long long
,也只生成了一个0
-initialization 代码。
结论
所以总而言之,如果你想默认构造原始类型/POD,就像使用0
.