2018年02月16日(金) [長年日記]
■ [c++] C++の可変引数テンプレートを使いこなせない
C++の可変引数テンプレートの使い方を覚えられないのでメモ。
昨日のコードでは可変長の引数を受け取るのに initializer_list を使ったが、可変引数テンプレートを使えば呼び出し側の
select(L"パタトクカシーー", {1, 3, 5, 7})
にある中括弧を無くせる。一応次のように書けるのだけれど、少し問題がある。
#include <iostream>
#include <numeric>
#include <string>
// sからindexesで指定された位置の文字を繋いだ文字列を返す。
template<typename... Args>
auto select(const std::wstring& s, Args... indexes)
-> decltype(std::initializer_list<int>({indexes...}), std::wstring{})
{
std::initializer_list<int> is{indexes...};
return std::accumulate(
is.begin(),
is.end(),
std::wstring{},
[&s](auto& result, auto i) { return result + s.at(i); });
}
int main()
{
std::ios_base::sync_with_stdio(false);
std::wcout.imbue(std::locale(""));
std::wcout << select(L"パタトクカシーー", 1, 3, 5, 7) << std::endl;
}
- C++ で特定の型での可変長引数を受け取るの真似をして、decltypeを使ってindexesをint列に変換できることをチェックしている。このチェックがなくても動くが、indexesに誤った型の値が設定されたときのエラーメッセージが分かりやすくなる(気がする)。
問題点は、昨日のコードはselect()の引数に負の数を指定したときにコンパイルエラーになったのに、上のコードはならないこと。initializer_list<> に与える型を int ではなく size_t にすれば解決するかと思ったが、それだと呼び出し側を
select(L"パタトクカシーー", 1u, 3u, 5u, 7u)
のように書かないとコンパイルエラーになるようになってしまう。
可変引数テンプレートはなかなか使いこなせるようにならない。
[ツッコミを入れる]