2011-08-11 14 views
17

多くの人と同様に、私はかなりC++0xに興奮しています。私は新しいプロジェクトで新しい機能を学び、それを使用しようとしているので、最も簡単で維持しやすいコードを書くことができます。C++ 0x均一初期化 "oddity"

言うまでもなく、新しいイニシャライザの背後にあるアイデアが大好きです。だから私は彼らを見ていて、これらは、私には意味をなさない:奇妙な

T x{1, 2, 3}; 

それだけで感じている...:

T x = { 1, 2, 3 }; // like a struct or native array 
T x({1, 2, 3}); // copy construct something like an "object literal" in other languages... cool! 
return {1, 2, 3}; // similar to above, but returning it, even cooler! 

は何私には意味がないことは、このです。私は、これが模倣していることを人々がどのような構文で使用したいのか分かりません。ただ正しいとは思われません。

この構文の背景には何がありますか?

違いを作るように思える唯一の例では、このようなものです:

std::vector<int> the_vec = {4}; 

:初期化子リストのコンストラクタを呼び出すが、なぜただ、その後これを書いていないでしょう

std::vector<int> the_vec{4}; 

誰もがすでに快適にしていることをしてください。

答えて

26

この構文の背景には何がありますか? C++ 03では

T x(); // function declaration 
T x{}; // value-initialized object of type 'T' named 'x' 

、あなたがこれに取得することができ、最も近いが必要どちらもT x((T()));またはT x = T();、次のとおりです。

一つには、ブレースの構文は、それが可能に厄介なパースを避けるために作りますTにはアクセス可能なコピーコンストラクタがあります。

+0

を検討し、彼らは**だけ**最も厄介なパースを「修正」するために、初期化のために全く新しい構文を追加していない私に教えてください: - /。 –

+0

まあ、統一された初期化構文を持っているのは本当にいいです(または、それは本当にクールだと思いますが、私はまだそれを使用する機会はありませんでした:-P)。様々な厄介な構文解析( 'T x()'とその厄介な友人 'T x(T)')のために、一様な初期化構文のための括弧として括弧を使うことはできません。ブレースにはこの問題はありません。 –

+6

@エヴァン:_uniform_ initializationと呼ばれる理由があります。それはどこでも同じように働くからです。 '{}'は "初期化"を意味します。それはその背後にある考えです。 –

19

まず、あなたが本当に一つのことには2種類あります。

T x = { 1, 2, 3 }; 
T x{1, 2, 3}; 

をこれら二つは実際にそれがexplicitコンストラクタを選択した場合、最初は無効であることを除いて同じ初期化を行っています。それ以外は同じです。最初は "コピーリスト初期化"と呼ばれ、2番目は "直接リスト初期化"です。

コンセプトは、=のフォームが3つの整数からなる値である「複合値」を割り当てていることです。そして、その値でxを初期化します。このような初期化のためには、  explicitコンストラクタ以外のもののみを許可する必要があります。 x{1, 2, 3}(等号なし)のコンセプトは、変数をという値で初期化することです。概念的には複合値ではなく、3つの別々の値をまとめて一度に与えることです。その言葉の最も一般的な意味での "コンストラクタ呼び出し"と言うことができます。

あなたが示した他の初期化は、実際に上記の二つは全く異なるものです:それは唯一の引数として{1, 2, 3}Tのconstuctorsを呼び出す

T x({1, 2, 3}); 

Tが配列の場合は配列を初期化するか、Tが集合体struct /クラスの場合は構造体メンバを初期化するなどの工夫はしていません。 Tがクラスでない場合、その宣言は無効です。しかし、Tにコピーまたは移動コンストラクタがある場合、そのコンストラクタを使用してコピーリストの初期化によって一時的なTを作成し、コピー/移動コンストラクタ参照パラメータを一時的にバインドすることができます。私はあなたが本当のコードでそのフォームをしばしば必要としないと信じています。


これはすべて、イニシャライザリストの委員会提案書に記録されています。私たちは、著作 初期化とダイレクトの違いを認識している専門家のプログラマことを観察した

:このケースでは、「初期化種類のプログラマの視点」セクションで、Initializer Lists — Alternative Mechanism and Rationaleを見てしたいです前者は後者よりも効率が悪いと誤って考えることがよくあります。 (実際には、両方の初期化が意味をなすとき、彼らは同じように効率的である。)

私たちは、別の観点からこれらの事を考えることがより有用であることが、対照的に、見つける:呼び出すことによって構築

  • コピー」のコンストラクタ(「CTOR-CALL」)値(「変換」)を転送することによって構築

(それが起こるように、「直接初期化」に相当し、前者、後者 - 初期化 "となりますが、st andardの用語は、プログラマを助けることはありません。)

その後、彼らは我々が単一の値として

X x = { ... }; 

{ ... }を治療するので、それがないことを

注意を見つけます

X x{ ... }; 

ここで、{ ... }はコンストラクタ呼び出しの引数リストです(N2531とは違うので、これを強調しています)。

C++ 0x FDISに記載されているルールは、このペーパーで提示されているものと若干異なりますが、そのペーパーに示されている根拠はC++ 0x FDISに保持されています。

+1

質問... '明示的な'コンストラクタを選択すると、最初のフォームが無効であることが言及されています。そして、2番目のパラグラフでは、 '明示的な'コンストラクタのみが最初のフォームに許可されるべきです。これらの2つのステートメントは互いに矛盾しているようです。彼らがそうでない場合、なぜこれが事実であるかをさらに説明できますか? – Jason

+0

@Jason、ありがとう。それを私が直した。 :) –

4

理論的な見地からは、与えられた答えは素晴らしいですが、実用的な例が役に立つかもしれません。統一された初期化により、これまで不可能だった構造を書くことが可能になりました。例:

  • メンバー配列を初期化します。

  • グローバル定数コンテナ(マップなど)。ウィットに

class Foo 
{ 
    int data[3]; 
public: 
    Foo() : data{1,2,3} { } 
}; 

ここでは、(デフォルトの建設が利用できない状況を考える)の割り当てを必要とせずに、直接メンバーの配列を初期化することができます。

const std::map<int, std::string> labels { 
    { 1 , "Open" }, 
    { 2 , "Close" }, 
    { 3 , "Reboot" } }; 

読み取り専用のグローバルルックアップオブジェクトが便利な場合もありますが、均一な初期化を行わずにデータで埋め込むことはできません。

+0

しかし、これらの例では、 'data({1,2,3})'と 'const std :: map というラベル({...}を書くことができませんでした。 。});そして人々(少なくとも私)が期待するものと同意したままでいるか? –

+0

@Evan:配列(または集合体)の場合、コンストラクタ構文がないので、 'data({1,2,3}) 'を持つことはできません。コンテナの場合は、かっこでILを書くこともできますが、これは代替です。 –

+0

確かに、配列にコンストラクタの構文を追加するほうが好ましいでしょう。 –

1

私は構文統一はジェネリックプログラミングでは非常に重要だと思います。これは良い答えですが例えば、

#include <utility> 
#include <tuple> 
#include <vector> 

template <class T> 
struct Uniform { 
    T t; 
    Uniform() : t{10, 12} {} 
}; 

int main(void) 
{ 
    Uniform<std::pair<int, int>> p; 
    Uniform<std::tuple<int, int>> t; 
    Uniform<int [2]> a; 
    Uniform<std::vector<int>> v; // Uses initializer_list 

    return 0; 
} 
+0

これは良い答えです。だから+1しますが、より良い解決ができたと思います。私は個人的に好きだったでしょう(私の意見は本当に重要ではないことは分かっています)。 ** all **型がコンストラクタ/コピーコンストラクタ構文(配列を含む)で初期化され、ユーザが他のlangが "オブジェクトリテラル"と呼ぶものを渡した場合。あなたの例では、 't({10,12}){}'です。私はそれが言語とより一貫していると思います。 –

+0

悲しいことに、uniformはstd :: array を初期化できません。 std :: arrayにはstd :: initializer_listコンストラクタがありません – Sumant