期待される振る舞いについて明確な答えが欲しかったので、に質問を投稿してcomp.lang.c++.moderated
、見返りにいくつかの素晴らしい答えを得ました。 ですから、情報を提供してくれたJohannes Schaub、Alf P. Steinbach(どちらもSO出身)、FrancisGlassborrowに感謝します。
これはGCCのバグではありません-実際、複数のコンパイラにまたがって壊れます-GCC 4.6、GCC 4.7、およびClangは、次のprimary expression expected before '('
構文を試した場合のように、同様のエラーについて文句を言います。
long long x = long long();
一部のプリミティブにはスペースがあり、バインディングのためにコンストラクタースタイルの初期化を使用する場合は許可されません(long()
バインドされていlong long()
ますが、空きがありますlong
)。(のように)スペースが含まれる型は、 -construction形式long long
を使用できません。type()
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
JohannesがC++11で「bordツール」と呼んでいるものを使用する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
が配列型の場合、各要素はデフォルトで初期化されます。
—それ以外の場合、オブジェクトはゼロで初期化されます。
、、、、などはすべてスカラー/ PODタイプであるためlong long
、最後の句はここで最も重要です。したがって、次のように呼び出します。unsigned long
int
float
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
したがって、上記で生成されたコードツリーから、コンストラクタースタイルのデフォルトの初期化を使用している場合でも、すべての変数がで初期化されていることに注意してint mi = int()
ください。GCCは、実行するだけのコードを生成しますint mi = 0
。
渡されたいくつかのデフォルトの構築を行おうとする私のテンプレート関数typename T
。ここで、も-初期化コードT = unsigned long long
だけを生成しました。0
結論
したがって、結論として、プリミティブ型/ PODをデフォルトで構築する場合は、を使用するようなもの0
です。