引数を使用して関数を宣言し、引数のデフォルト値が型のデフォルトコンストラクターの結果であることを指定したい場合があります。
void foo(a::really::long::type::name arg = a::really::long::type::name());
タイプ名を2回入力する必要のない、より優れた構文はありますか?何かのようなもの:
void foo(a::really::long::type::name arg = default);
タイプ名をtypedef
してきれいにすることができると思いますが、そのような構文が存在するかどうか知りたいです。
はい:
void foo(a::really::long::type::name arg = {});
次の標準的な定義を要約すると:
これはリストの初期化です。タイプに応じて、集計の初期化が実行されるか、オブジェクトが値の初期化されます。これは、デフォルトの初期化またはゼロの初期化を意味します。
一部の「コーナー」ケースは、型がstd::initializer_list
の特殊化である場合、または型にstd::initializer_list
コンストラクターがある場合です(デフォルトのコンストラクターがない場合に呼び出されます)。
関連する標準引用符(定義に遭遇するため):
§8.3.6デフォルトの引数[dcl.fct.default]
1初期化句がパラメータ宣言で指定されている場合、この初期化句がデフォルトの引数として使用されます
5デフォルトの引数には、コピー初期化セマンティクス(8.5)を使用した、パラメーター型の変数の宣言におけるイニシャライザーと同じセマンティック制約があります。
§8.5.4リストの初期化[dcl.init.list]
1リスト初期化は、braced-init-listからのオブジェクトまたは参照の初期化です。このような初期化子は、初期化子リスト[...]と呼ばれます。初期化子リストが空の場合があります。リストの初期化は、直接初期化またはコピー初期化のコンテキストで発生する可能性があります。 [..]コピー初期化コンテキストでのリスト初期化は、コピーリスト初期化と呼ばれます。
3タイプTのオブジェクトまたは参照のリスト初期化は、次のように定義されます。
- Tが集合体の場合、集合体の初期化が実行されます(8.5.1)
- それ以外の場合、初期化子リストに要素がなく、Tがデフォルトのコンストラクターを持つクラス型である場合、オブジェクトはvalue-initializedです。
- それ以外の場合、Tがstd :: initializer_listの特殊化である場合、prvalue initializer_listオブジェクトは以下に説明するように構築され、同じタイプのクラスからのオブジェクトの初期化のルールに従ってオブジェクトを初期化するために使用されます(8.5)。
- それ以外の場合、Tがクラス型の場合、コンストラクターが考慮されます。該当するコンストラクターが列挙され、オーバーロード解決(13.3、13.3.1.7)によって最適なコンストラクターが選択されます[...]
- .。
- それ以外の場合、初期化子リストに要素がない場合、オブジェクトはvalue-initializedです。
§8.5イニシャライザー[dcl.init]
8 To value-initializeタイプTのオブジェクトは、次のことを意味します。
- tが(おそらくcv修飾された)クラスタイプ(条項9)であり、デフォルトコンストラクター(12.1)がないか、ユーザー提供または削除されたデフォルトコンストラクターがある場合、オブジェクトはdefault-initialized ;
- tがユーザー提供または削除されたデフォルトコンストラクターのない(おそらくcv修飾された)クラスタイプである場合、オブジェクトはzero-initializedであり、default-initializationのセマンティック制約がチェックされます。重要なデフォルトコンストラクタがあり、オブジェクトはdefault-initialized;
- tが配列型の場合、各要素はvalue-initialized;
- それ以外の場合、オブジェクトはゼロ初期化
7 To default-initializeタイプTのオブジェクトは次のことを意味します。
- tが(おそらくcv修飾された)クラスタイプの場合(第9節)、Tのデフォルトコンストラクター(12.1)が呼び出されます(Tにデフォルトコンストラクターまたはオーバーロードがない場合、初期化の形式が正しくありません解決(13.3)は、あいまいさ、または初期化のコンテキストから削除された、またはアクセスできない関数をもたらします。
- tが配列型の場合、各要素はdefault-initialized;
- それ以外の場合、初期化は実行されません。
6 To zero-initializeタイプTのオブジェクトまたは参照は、次のことを意味します。
- tがスカラー型(3.9)の場合、オブジェクトは整数リテラル0(ゼロ)をTに変換して得られた値に初期化されます。
- tが(おそらくcv修飾された)非ユニオンクラスタイプの場合、各非静的データメンバーと各基本クラスサブオブジェクトはゼロで初期化され、パディングはゼロビットに初期化されます。
- tが(おそらくcv修飾された)共用体型である場合、オブジェクトの最初の非静的名前付きデータメンバーはゼロで初期化され、パディングはゼロビットに初期化されます。
- tが配列型の場合、各要素はゼロで初期化されます。
- tが参照型の場合、初期化は実行されません。
§13.3.1.7リストによる初期化-初期化[over.match.list]
1非集約クラスタイプTのオブジェクトがリストで初期化される場合(8.5.4)、過負荷解決は2つのフェーズでコンストラクターを選択します。
- 最初、候補関数はクラスTのinitializer-listコンストラクター(8.5.4)であり、引数リストは単一の引数としての初期化子リストで構成されます。
- 実行可能な初期化子リストコンストラクターが見つからない場合、オーバーロード解決が再度実行されます。候補関数はクラスTのすべてのコンストラクターであり、引数リストは初期化子リストの要素で構成されます。
初期化子リストに要素がなく、Tにデフォルトのコンストラクターがある場合、最初のフェーズは省略されます。 [...]
arg
のクラスを制御すれば、歩行者アプローチが可能です。 enum
に対してオーバーロードされた変換コンストラクターを使用します。
// Define this enum, and then write constructors which take dfl
enum dfl { dflval };
class a_really_long_type_name {
public:
a_really_long_type_name(dfl arg = dflval);
};
現在、fooは次のようになります。
void foo(a_really_long_type_name arg = dflval);
これを適用できる場合、利点は移植性です。これは、25年前のC++コンパイラで正常に機能するはずです。
複数のクラスはすべて、このdfl
enum
とそのdflval
フレーバーのゼロを共有できます。それは新しいキーワードを持っているようなものです。
enum
は別個の型であるため、整数型や文字などのコンストラクターのオーバーロードに干渉しません。
欠点は、引数のデフォルト設定によってデフォルトの構造がすでに提供されているいくつかのクラスにそれを組み込むことです。これにより、コンストラクターコードが重複します。