【C++】コンストラクタで可変長引数を実現する方法

複数の方法を紹介します。# initializer_listを用いた方法がオススメです。# 可変引数テンプレートを用いた方法もあります。

initializer_list

C++11の新機能です。コンストラクタ側で初期化リストを受け取ります。

struct Sum {
  int sum;
  Sum(std::initializer_list<int> list) : sum(0) {
    for (auto a : list) sum += a;
  }
};
int main() {
  Sum a{1, 2, 3};
  Sum b = {1, 2, 3};
  a.sum; // 6
  b.sum; // 6
}

第二引数以降を用いたコンストラクタ呼び出しが行えない点に注意が必要です。

// ERROR: No matching constructor for initialization of 'Sum'
Sum c = Sum(1, 2, 3);
// OK
Sum d = Sum({1, 2, 3});

イニシャライザリストは他にも様々な方法で処理することが出来ます。

struct Sum {
  int a, b, c;
  std::vector<int> d;
  Sum(std::initializer_list<int> list)
    : a(0), b(0), c(0),

    // vectorのコンストラクタでコピーする方法
    d(list.begin(), list.end())
  {
    // for文で回す方法(イテレータ編)
    for (auto p = list.begin(); p < list.end(); ++p)
      a += *p;

    // for文で回す方法(インデックス編)
    for (size_t i = 0, c = list.size(); i < c; i++)
      b += list.begin()[i];

    // for_each関数で計算する方法
    std::for_each(list.begin(), list.end(), [&](int v) {
      c += v;
    });
  }
};

可変引数テンプレート

扱いに工夫が必要になるため、基本的にはinitializer_listを用いるのがオススメです。

コンストラクタ側で受け取った可変長テンプレート引数を静的メンバ関数等で処理します。

struct Sum {
  int v;
  A() : v(0) {}
  
  // コンストラクタ
  template<class... Args>
  Sum(Args... args) : v(sum(args...)) {}
  
  // 静的メンバ関数
  template<class T>
  static int sum(T v) { return v; }
  
  template<class T, class... Args>
  static int sum(T v, Args... args) { return v + sum(args...); }
};
Sum x{};
Sum a{1, 2, 3};
Sum b = {1, 2, 3};
Sum c(1, 2, 3);
Sum d = Sum(1, 2, 3);

x.v; // 0
a.v; // 6

initializer_listの時とは違い、第二引数以降を使用したコンストラクタ呼び出しが行えます(Sum(1, 2, 3);)。

広告