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 ✅