5

vialong longを構築するのと同様に、gccでどのように構築しますかintint()

以下はgcc(4.6.3 20120306)で失敗します(ただし、たとえばMSVCを渡します)。

myFunctionCall(someValue, long long());

エラーありexpected primary-expression before 'long'(列の位置は最初の長さが位置であることを示します)。

簡単な変更

myFunctionCall(someValue, (long long)int());

正常に動作します-つまり、コンストラクターintとキャスト先-gcclong longがctorを好まないことを示しlong longます。

要約ソリューション

@birryreeからの以下の素晴らしい説明を要約すると:

  • 多くのコンパイラはサポートlong long()しておらず、標準に準拠していない可能性があります
  • 構築long longはリテラルと同等0LLであるため、myFunctionCall(someValue, 0LL)
  • typedef long_long_t long longまたは、 thenを使用しますlong_long_t()
  • 最後に、少なくとも64ビットであるが、プラットフォームによって異なる可能性があるタイプではなく、任意のプラットフォームで正確に64ビットであるタイプを使用uint64_t する場合は使用を検討してください。
4

1 に答える 1

5

期待される振る舞いについて明確な答えが欲しかったので、に質問を投稿して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 longlinux-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 longintfloat

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です。

于 2012-05-10T15:54:23.453 に答える