2012-03-01 4 views
4

におけるPODとの暗黙の型変換の初期化:デフォルトコンストラクタ、私はちょうど彼が次のコードを提示ネイティブ2012を行くのクランにチャンドラーのプレゼンテーションを見ているC++ 11

#include <iostream> 

struct S{ int n; }; 
struct X{ X(int) {}; }; 

void f(void*) 
{ 
    std::cerr << "Pointer!\n"; 
} 

void f(X) 
{ 
    std::cerr << "X!\n"; 
} 

int main() 
{ 
    f(S().n); 
} 

チャンドラーが、これはf(void*)を呼び出すと述べているがC++ 11の場合はf(X)、C++ 03の場合はf(X)。 彼はまた、S()。nはデフォルトで0に初期化され、nullptrという定数になっているという理由も述べています。

最初に、メンバー変数nのゼロ初期化がコンパイラの実装に依存していて、標準によって保証されていないと仮定しています(またはこの変更はC++ 11で行われましたか)。チャンドラーは、これは定数式のサポートによるものだと思っていますが、私はまだ彼の推論に完全に従うことができません。

第2に、f(X)はなぜC++ 03で呼び出され、C++ 11では呼び出されないのですか?

Clang: Defending C++ from Murphy's Million Monkeys

答えて

9

まず私は、右のメンバー 変数nのゼロ初期化が依存して によって標準を保証していません(またはC++ 11と、この変更をした)コンパイラの実装であると仮定していますか?

いいえ、S()は、値がC++ 03とC++ 11の両方で初期化されることを意味します。私はこの言葉がC++ 11ではC++ 03よりはるかに明確であると信じていますが。この場合、値の初期化はゼロ初期化に転送されます。ないデフォルトの初期化とは対照的ではないゼロ:

第二に、なぜF(X)C++ 03とではないC++ 11と呼ばれることになる
S s1; // default initialization 
std::cout << s1.n << '\n'; // prints garbage, crank up optimizer to show 
S s2 = S(); // value initialization 
std::cout << s2.n << '\n'; // prints 0 

? I のだろう)(void *型)fは関係なく、Sの値(のでキックすると仮定。X

への暗黙的な変換を超えるN C++で03 intはNULLポインタになることはありません定数。 0intと入力されると、それをintに割り当てると、それは永遠にintであり、NULLポインタ定数ではありません。 C++ 11では

S().nは暗黙値0constexpr式であり、値0constexpr式がヌルポインタ定数とすることができます。

最後に、私が言う限り、これは委員会の意図的な変更ではありません。この違いに依存するコードを書いているなら、委員会がそれを訂正した場合には、将来的に噛まれる可能性があります。私はこの分野をはっきりと操るだろう。プロダクションコードではなく、バーベットに勝つために使用します。

+0

欠陥報告がこれにまだ提出されているかどうか知っていますか?私は何も見ていないが、私はそれを逃した可能性があります。 – bames53

+0

ありがとう、私は決してチャンドラーのプレゼンテーションを見た後、興味のあるようなコードを書くことはありません... – mark

+0

ああNVM私は今、 "int"とあなたは "int変数"を意味します。私は混乱していて、 "0"はintではない、またはint式は決してnullポインタ定数ではないと言っていると思っていました。 –

5

まず、いくつかの明確化:私はf(void*)はチャンドラーの説明は次のリンクを参照してください、X

に暗黙的な変換の上に関わらずS().nの値の中に蹴る45分であろうと仮定するでしょうその後

// This is default construction 
S s; 
// s.i has undefined value 

// This is initialization from a value-initialized S (C++03 rules) 
S s = S(); 
// s.i has been zero-initialized 

// This is value initialization (C++11 rules) 
// new syntax, better rules, same result 
S s {}; 
// s.i has been zero-initialized 

intということを覚えている:C++ 03とC++ 11の両方のための初期設定のルールにに変換できませんので、C++で03 f(S().n)となります。となります。その他の宣言はfがない場合でも、となります。 C++ 03で可能です何

void f(X);が存在する場合であってもvoid f(void*);を呼ぶであろう、f(0)を行うことです。これは、ゼロ積分定数 - >void*の変換(UD変換ではない)よりも、int - >Xの変換(いわゆるユーザー定義変換)よりも好ましくないことです。 int()もゼロ積分定数であるため、をf((int()))経由で呼び出すこともできます(C++ 03でも)。 (通常のように、括弧は構文上のあいまいさを解決するためのものです。)

C++ 11の変更点は、今やS().nはゼロ積分定数です。これは、S()が定数式になりました(の一般化定数式のおかげで)、この種のメンバーアクセスもあります。

関連する問題