namespace std {
// C++17
template <class T, class Tuple>
constexpr T make_from_tuple(Tuple&& t);
// C++23
template <class T, tuple-like Tuple>
constexpr T make_from_tuple(Tuple&& t);
}
概要
tuple-likeな型Tupleのオブジェクトに含まれる値から型Tのオブジェクトを構築する。
要件
型Tのコンストラクタの内のいずれか一つが、型Tupleに含まれる全ての型の値をその順番通りに受け入れ可能であること。それができない場合はコンパイルエラーとなる。
また、型Tの初期化はそのコンストラクタで行われ集成体初期化は考慮されない。つまり、Tupleに含まれる型が空かただ一つのTでない場合、型Tは集成体(aggregate)であってはならない(C++17のみ、C++20以降はok)。
更に、C++23以降はmake_from_tupleの戻り値が参照である場合でダングリング参照を生成しないために、make_from_tupleの内部でTが構築される際に、Tupleから取得されるオブジェクト(参照の初期化であるので、Tupleのサイズは1である必要がある)の寿命が延長されないことも要求され、これを満たさない場合はコンパイルエラーとなる。
正確には、tuple_size_v<remove_reference_t<Tuple>> == 1である場合、reference_constructs_from_temporary_v<T, decltype(get<0>(declval<Tuple>()))> == falseであること。
引数
t--tuple-likeな型Tupleのオブジェクト
tuple-likeな型とは主にstd::tupleの事であるが、std::pairやstd::arrayのようにstd::tupleと同じような扱いができる型も含んでいる。
より詳細には、std::get(インデックス指定)とstd::tuple_sizeが適用可能な型である。(C++20まで。)C++23 ではtuple-likeによる制約が追加されたため、使用できる型は狭まった。(tuple-likeを参照)
戻り値
Tupleに含まれる型の値をその順番通りに型Tのコンストラクタにstd::forwardして構築されたTのオブジェクト。
例外
Tupleに含まれる型の値を受け取るTのコンストラクタが例外を送出する可能性がある場合は、この関数も例外を送出しうる。
備考
構築したい型Tは引数からの推論ができないので、明示的に指定する必要がある。
また、値のコピー省略保証に対応するコンパイラであれば型Tはムーブ可能である必要はない(戻り値のTのオブジェクトは呼び出し元で構築される)。
実装例
template<class T, class Tuple, std::size_t... Index>
constexpr T make_from_tuple_impl(Tuple&& t, std::index_sequence<Index...>){
return T(std::get<Index>(std::forward<Tuple>(t))...);
}
template <class T, class Tuple>
constexpr T make_from_tuple(Tuple&& t) {
return make_from_tuple_impl<T>(std::forward<Tuple>(t), std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tuple>>>{});
}
例
#include <tuple>
#include <array>
#include <iostream>
struct sample {
sample(int a, int b, double c, const char* d) {
std::cout << a << ", " << b << ", " << c << ", " << d << std::endl;
}
sample(int a, double b) {
std::cout << a << ", " << b << std::endl;
}
sample(int a1, int a2, int a3, int a4) {
std::cout << a1 << ", " << a2 << ", " << a3 << ", " << a4 << std::endl;
}
//あらゆるムーブ・コピー操作をdelete
sample(sample&&) = delete;
sample(const sample&) = delete;
sample& operator=(sample&&) = delete;
sample& operator=(const sample&) = delete;
};
int main()
{
{
auto t = std::make_tuple(0, 10, 20.0, "Hello world.");
//std::tuple<int, int, double, const char*>からの構築
auto s = std::make_from_tuple<sample>(std::move(t));
}
{
auto p = std::make_pair(30, 40.0);
//std::pair<int, double>からの構築
auto s = std::make_from_tuple<sample>(std::move(p));
}
{
std::array<int, 4> a = {1, 2, 3, 4};
//std::arrayからの構築
auto s = std::make_from_tuple<sample>(std::move(a));
}
}
出力
0, 10, 20, Hello world.
30, 40
1, 2, 3, 4
バージョン
言語
- C++17
処理系
- Clang: ??
- GCC: ??
- Visual C++: 2017 ✅