2026/01/20(火)cpprefjpを読もう。【一様初期化】

一様初期化 [N2672] cpprefjp

概要

一様初期化(uniform initialization)は、コンストラクタの呼び出しを
リスト初期化と合わせて波カッコで記述する構文。

リスト初期化は前回確認した初期化子リストで取り上げた。cppref

この機能により、戻り値の型が確定している文脈において、コンストラクタの引数を波カッコ内に列挙したものをreturnで返せるようになる。その際に、戻り値の型を記述する必要がない。(初期化子リストのみで良い)

仕様
  • 初期化子リストautoで受けた場合、その型はstd::initializer_list<T>に推論される。
    C++14/17以降では、要素数1の初期化子リストstd::initializer_list<T>に対し、

    • コピー初期化した場合、std::initializer_list<T>型に推論される。
    • 直接リスト初期化した場合、T型に推論される。
      wandbox
  • 関数テンプレートのパラメータとして、初期化子リストを渡して推論はできない。
    wandbox
    template<class T> void sample([[maybe_unused]]T param){};
    int main()
    {
        //sample({1,2,3}); // エラー
        sample(std::initializer_list<int>{1,2,3});
        return 0;
    }
    
  • 関数のパラメータの型が確定している場合は、初期化子リストを渡せる。
  • 関数の戻り値の型が確定している場合は、初期化子リストをreturnできる。
  • 初期化子リストコンストラクタと同じ型のパラメータをとるコンストラクタがある場合、
    リスト初期化を使用した場合は初期化子リストコンストラクタが優先され、
    そうでないコンストラクタを呼び出す場合は、丸カッコを使用する。
補足

丸カッコによる初期化は、意図せず関数宣言構文とみなされる場合がある。
波カッコによる初期化を行うことで、コンストラクタによる初期化を明示できる。

参考

【C++】初期化子リスト関連機能を大雑把に理解する

2026/01/19(月)cpprefjpを読もう。【初期化子リスト】

C++11 初期化子リスト [N2672] cppref

概要

ユーザー定義型オブジェクトに対して、波カッコによるリスト初期化が可能になる機能。

ユーザー定義型 : 標準ライブラリの型を除く、ユーザーによって定義された型

<initializer_list>ヘッダに定義されたstd::initializer_listをパラメータとして、
コンストラクタや代入演算子をオーバーロードする。

cppref std::initializer_list

つまるところ、任意の型に対してリストのようにイテレータアクセスを可能にしたクラス
(内部実装はコンパイラ側にあって、不明)
貰ったstd::initializer_list<T>のイテレータで良しなに初期化しろっていうことか。

仕様

重要そうなものを抜粋

  • 波カッコを使用した初期化子のリストによる、オブジェクトもしくは参照の初期化をリスト初期化 (list initialization)と呼ぶ。
  • 上記の初期化子を初期化子リスト (initializer list)と呼ぶ。
  • 初期化子リスト (initializer list)は、カンマ区切りで要素を列挙する。
  • 初期化子リスト (initializer list)は、空であってもよい。
  • 使用できる個所は、このクラスを使ってオーバーロードしたコンストラクタや演算子等。
  • 初期化子リストに 縮小変換 が要求された場合、プログラムは不適格となる
    試しにvectorで見てみる。 wandbox
    結果は仕様通り。
    prog.cc: In function 'int main()':
    prog.cc:7:49: error: narrowing conversion of '5.0e+0' from 'double' to 'int' [-Wnarrowing]
        7 |     std::vector<int> container2 {1, 2, 3, 4, 5.0};
        |           
    
  • 以下の条件を満たすコンストラクタを初期化子リストコンストラクタ(initializer-list constructor)と呼ぶ
    1. 任意の型を要素とする初期化子リストのみを引数とする物。
    2. 任意の型の初期化子リストおよび、それ以降にデフォルト引数を持つ物。
  • オーバーロード解決
    • デフォルトコンストラクタ初期化子リストコンストラクタがある場合、
      空の初期化子リストが渡された場合はデフォルトコンストラクタが呼び出される。
余談

gptを使用してブログのレビューしたんだが、以下のような指摘を受けた。

オーバーロード解決の説明
デフォルトコンストラクタと初期化子リストコンストラクタがある場合、
空の初期化子リストが渡された場合はデフォルトコンストラクタが呼び出される。
⚠ これは誤りです(重要)
正しい仕様
  • 初期化子リストコンストラクタが存在する場合
    • {} は initializer_list コンストラクタが優先される
  • デフォルトコンストラクタが呼ばれるのは:
    • initializer_list コンストラクタが存在しない場合

へーそうなんすね、調べてみましょう。
wandbox コード

#include <iostream>
#include <vector>
#include <initializer_list>

template<class T>
class Test
{
public:
    Test()
    {
        std::cout << "default" << std::endl;
    }

    Test([[maybe_unused]] std::initializer_list<T> l)
    {   
        std::cout << "initializer_list" << std::endl;
    }
};

int main()
{
    Test<int> test_default;
    Test<int> test_initilizer {1, 2, 3, 4};
    Test<int> test_empty {};
}

結果

default
initializer_list
default

嘘じゃねーか!
課金しないとモデル選択できないとは言えさぁ...
ちなみにgemini-3-flashは特に変なことは言っていなかった。
いい加減、AI使うなら課金しないといけないか...

2026/01/18(日)cpprefjpを読もう。【範囲for文】

C++11 範囲for文 [N2930] cppref

概要

配列、連想コンテナを簡潔に扱うための表現。

std::vector<int> buff;

for(auto e : buff)
{
    std::cout << e << std::endl;
}

注意すべきところは受けとる変数の型指定。
配列なんかを添字でアクセスするのとは違い、(必要ならば)明示的に参照をする必要がある。
重いクラスを扱う際に不必要なコピーが発生していないか注意したい。
cppref上にわかりやすい図があったのでそのまま引用する。

変数宣言 eを変更可能か コンテナ要素を変更可能か
const auto& e NO NO
auto& e YES YES
auto e YES NO
仕様

begin()からend()までの範囲に含まれる要素に対し処理を実行する。

使用上の注意
  • 範囲for文内でコンテナ要素を追加/削除するとイテレータが無効になる場合がある。
  • for-range-initializerに渡したものの寿命が切れてイテレータが無効になる場合がある。
    初期化子リストもC++11の機能で、ちょうど次回確認する。

2026/01/15(木)cpprefjpを読もう。【decltype】

C++11 decltype [N2343] cpprefjp

仕様

C++11の機能、指定した式の型を取得できる。

typeofと何が違うのかと思ったのだが、typeofは非標準な仕様らしい。
知らなかった...
C言語ではC23にて標準仕様に取り込まれたらしい。(めちゃ最近の話だ...)

typeof演算子 in 標準C - yohhoyの日記 - はてなブログ
typeofと比較して仕様の違い。
  1. 参照の扱い

    • decltypeはオペランドの型にある参照を保存する。
    • typeofはオペランドの型にある参照を外す。
      wandbox
      左辺値への参照型に対して型を取得した場合、
      decltype(int&)int&を示し、
      typeof(int&)intを示す
  2. 使用可能な場所

    • typeofは変数宣言時のみ使用可能
    • decltypeは型名が使用できる場所はどこでも使用可能
  3. オペランドの種類

    • typeofは式と型を使用可能
      例) typeof(int)typeof(a + b)

    • decltypeは式のみ使用可能
      例) decltype(a + b)
追記

C++11の以下機能の組み合わせで使用しているのを見かける
変数の型推論のための auto
decltype
戻り値の型を後置する関数宣言構文

auto function(int a, int b) -> decltype(a + b)
{
    return a + b;
}

2026/01/14(水)cpprefjpを読もう。【変数の型推論のためのauto】

C++11 変数の型推論のためのauto [N1984] cpprefjp

C++11からの機能で、変数宣言時に具体的な型名を省略して宣言できる。
個人的にはユーザー定義クラスを使用する時に使用する印象。
ある程度短い型名ではわざわざ使わないかも。uint16_tとか...

auto container = std::vector<std::pair<uint8_t, uint16_t>>();
auto user_class = UserDefineClass<uint32_t>();

仕様

auto による型推論は、以下の場所で初期化子がある場合のみ使用可能である。
  • ブロックスコープでの変数宣言
  • 名前空間スコープでの変数宣言
  • for 文の初期化文部での変数宣言
  • if 文、 switch 文、 for 文、 while 文の条件部での変数宣言
  • new 式の型名指定部
  • クラス定義内での静的メンバ宣言

なんとなく変数の初期化で使用できるイメージだが、使用できないケースについてGeminiで確認した。
が、思考モードにしても結構適当言われたので無課金だとあんまり当てにならないな...
cpprefjpを適当でもだらだら見ていなかったら気づかんかったな
以下内容は一応整合性は確認した。

autoが使用できないケース
  • 関数引数
    確かに、あまり見たことない気がする。
    C++14でジェネリックラムダ、C++20で関数テンプレートの簡易定義というものが追加され使用できるようになっているらしい。
    詳細はまたいずれ...

  • 非静的メンバ変数
    言われてみると関数内、式の中でしか見てないな。
    static constまたはstatic constexprの場合は使用可能らしい。
    wnadbox

  • 関数の戻り値
    C++11の機能戻り値の型を後置する関数宣言構文 [N2541]で表現可能。

    auto func() -> int {
        return 0;
    }
    

    以前、標準ライブラリのtype_traitsを見ていた時に結構見かけた。
    ただ、自分で実装する時に使用するかといわれると...
    現状あんまり有効活用できるイメージがない

  • 配列宣言
    初期化子リストとしては使用可能らしい。一応コード例 wandbox
  • テンプレート引数
    c++17からは使用可能らしい 非型テンプレートパラメータのauto宣言 [P0127R2]