私は次のコードを持っています:
bool c (a == b);
と
bool c {a == b};
ここで、a と b は同じ型の変数です。
上記の2つの初期化の違いと、どの条件でどちらを優先する必要があるかを知りたいですか? あらゆる種類の助けをいただければ幸いです。
私は次のコードを持っています:
bool c (a == b);
と
bool c {a == b};
ここで、a と b は同じ型の変数です。
上記の2つの初期化の違いと、どの条件でどちらを優先する必要があるかを知りたいですか? あらゆる種類の助けをいただければ幸いです。
どちらの形式も直接初期化です。
初期化チェックに中括弧{}
を使用すると、縮小変換が行われ、そのような変換が発生した場合にエラーが生成されます。とは異なり()
。( gcc はデフォルトで警告を発行し、ナ-Werror=narrowing
ローイングが発生したときにエラーを生成するにはコンパイラ オプションが必要です。)
中括弧のもう 1 つの用途{}
は、均一な初期化です。同じ構文を使用して、コンストラクターを使用する場合と使用しない場合の両方の型を初期化します。次に例を示します。
template<class T, class... Args>
T create(Args&&... args) {
T value{std::forward<Args>(args)...}; // <--- uniform initialization + perfect forwarding
return value;
}
struct X { int a, b; };
struct Y { Y(int, int, int); };
int main() {
auto x = create<X>(1, 2); // POD
auto y = create<Y>(1, 2, 3); // A class with a constructor.
auto z = create<int>(1); // built-in type
}
初期化に中括弧を使用する唯一の欠点は、キーワード{}
との相互作用です。これは既知の問題です。 「Auto and braced -init-lists」を参照してください。auto
auto
{}
std::initializer_list
1 つ目は、C++03 スタイルの直接初期化です。2 つ目は C++11 スタイルの直接初期化で、さらに縮小変換をチェックします。Herb Sutter は、新しいコードで次のことを推奨しています。
auto c = <expression>;
または、特定のタイプ T にコミットする場合:
auto c = T{<expression>};
T がオーバーロードされたコンストラクターを持つクラスである場合の中括弧の既知の欠点の 1 つは、1 つのコンストラクターがパラメーターとして std::initializer_list を取得する場合、たとえば std::vector です。
auto v = std::vector<int>{10}; // create vector<int> with one element = 10
auto v = std::vector<int>(10); // create vector<int> with 10 integer elements
これで、初期化の 5 つの形式ができました。彼らです
T x = expression;
T x = ( expression );
T x ( expression );
T x = { expression };
T x { expression };
それぞれのフォームには独自の特徴があります。:)
たとえば、グローバル名前空間に次の宣言があるとします。
int x;
void f( int x ) { ::x = x; }
int g() { return x ; }
long h() { return x; }
次に、主に書くことができます
int main()
{
int x ( g() );
}
このコードは正常にコンパイルされます。
しかし、プログラマーが間違ってタイプミスをした
int main()
{
int x; ( g() );
^^
}
おっとっと!このコードも正常にコンパイルされます。:)
しかし、プログラマーが書くなら
int main()
{
int x = ( g() );
}
そしてタイプミスをする
int main()
{
int x; = ( g() );
^^
}
この場合、コードはコンパイルされません。
プログラマーが、ローカル変数を初期化する前に、最初にグローバル変数 x に新しい値を設定することを決定したと仮定しましょう。
だから彼は書いた
int main()
{
int x ( f( 10 ), g() );
}
しかし、このコードはコンパイルされません!
等号を挿入しましょう
int main()
{
int x = ( f( 10 ), g() );
}
コードが正常にコンパイルされるようになりました。
ブレースはどうですか?
このコードも
int main()
{
int x { f( 10 ), g() };
}
このコードも
int main()
{
int x = { f( 10 ), g() };
}
コンパイル!:)
ここで、プログラマーは関数 h() を使用することに決めました。
int main()
{
int x ( h() );
}
彼のコードは正常にコンパイルされます。しかし、しばらくして彼はブレースを使用することにしました
int main()
{
int x { h() };
}
おっとっと!彼のコンパイラはエラーを出す
エラー: 非定数式は、イニシャライザ リストでタイプ 'long' から 'int' に絞り込むことができません
プログラムは、型指定子 auto を使用することにしました。彼は2つのアプローチを試みた
int main()
{
auto x { 10 };
x = 20;
}
と
int main()
{
auto x = { 10 };
x = 20;
}
そして...一部のコンパイラは最初のプログラムをコンパイルしましたが、2番目のプログラムをコンパイルしませんでした.一部のコンパイラは両方のプログラムをコンパイルしませんでした.:)
そして、使用についてはdecltype
どうですか?
たとえば、プログラマーが書いた
int main()
{
int a[] = { 1, 2 };
decltype( auto ) b = a;
}
そして、彼のコンパイラはエラーを出しました!
しかし、プログラマーが a をこのように括弧で囲むと
int main()
{
int a[] = { 1, 2 };
decltype( auto ) b = ( a );
}
コードは正常にコンパイルされました!:)
今、プログラマーは OOP を学ぶことにしました。彼は簡単なクラスを書いた
struct Int
{
Int( int x = 0 ) : x( x ) {}
int x;
};
int main()
{
Int x = { 10 };
}
彼のコードは正常にコンパイルされます。しかし、プログラマーは関数指定子があることを知っており、explicit
それを使用することにしました
struct Int
{
explicit Int( int x = 0 ) : x( x ) {}
int x;
};
int main()
{
Int x = { 10 };
}
おっとっと!彼のコンパイラはエラーを出しました
error: chosen constructor is explicit in copy-initialization
プログラマーは割り当て記号を削除することにしました
struct Int
{
explicit Int( int x = 0 ) : x( x ) {}
int x;
};
int main()
{
Int x { 10 };
}
そして彼のコードは正常にコンパイルされました!:)