constexpr tuple(); // (1) C++11
EXPLICIT constexpr tuple(); // (1) C++17
explicit(see below) constexpr tuple(); // (1) C++20
explicit tuple(const Types&...); // (2) C++11
constexpr explicit tuple(const Types&...); // (2) C++14
EXPLICIT constexpr tuple(const Types&...); // (2) C++17
explicit(see below) constexpr tuple(const Types&...); // (2) C++20
template <class... UTypes>
explicit tuple(UTypes&&...); // (3) C++11
template <class... UTypes>
constexpr explicit tuple(UTypes&&...); // (3) C++14
template <class... UTypes>
EXPLICIT constexpr tuple(UTypes&&...); // (3) C++17
template <class... UTypes>
explicit(see below) constexpr tuple(UTypes&&...); // (3) C++20
tuple(const tuple&) = default; // (4) C++11
tuple(tuple&&) = default; // (5) C++11
template<class... UTypes>
explicit(see below) constexpr tuple(tuple<UTypes...>&); // (6) C++23
template <class... UTypes>
tuple(const tuple<UTypes...>&); // (7) C++11
template <class... UTypes>
constexpr tuple(const tuple<UTypes...>&); // (7) C++14
template <class... UTypes>
EXPLICIT constexpr tuple(const tuple<UTypes...>&); // (7) C++17
template <class... UTypes>
explicit(see below) constexpr
tuple(const tuple<UTypes...>&); // (7) C++20
template <class... UTypes>
tuple(tuple<UTypes...>&&); // (8) C++11
template <class... UTypes>
constexpr tuple(tuple<UTypes...>&&); // (8) C++14
template <class... UTypes>
EXPLICIT constexpr tuple(tuple<UTypes...>&&); // (8) C++17
template <class... UTypes>
explicit(see below) constexpr tuple(tuple<UTypes...>&&); // (8) C++20
template<class... UTypes>
explicit(see below) constexpr
tuple(const tuple<UTypes...>&&); // (9) C++23
template<class U1, class U2>
explicit(see below) constexpr tuple(pair<U1, U2>&); // (10) C++23
template <class U1, class U2>
tuple(const pair<U1, U2>&); // (11) C++11
template <class U1, class U2>
constexpr tuple(const pair<U1, U2>&); // (11) C++14
template <class U1, class U2>
EXPLICIT constexpr tuple(const pair<U1, U2>&); // (11) C++17
template <class U1, class U2>
explicit(see below) constexpr tuple(const pair<U1, U2>&); // (11) C++20
template <class U1, class U2>
tuple(pair<U1, U2>&&); // (12) C++11
template <class U1, class U2>
constexpr tuple(pair<U1, U2>&&); // (12) C++14
template <class U1, class U2>
EXPLICIT constexpr tuple(pair<U1, U2>&&); // (12) C++17
template <class U1, class U2>
explicit(see below) constexpr tuple(pair<U1, U2>&&); // (12) C++20
template<class U1, class U2>
explicit(see below) constexpr
tuple(const pair<U1, U2>&&); // (13) C++23
template<tuple-like UTuple>
explicit(see below) constexpr tuple(UTuple&&); // (14) C++23
// 以下アロケータを指定する構築
template <class Alloc>
tuple(allocator_arg_t, const Alloc& a); // (15) C++11
template <class Alloc>
explicit(see below) constexpr
tuple(allocator_arg_t, const Alloc& a); // (15) C++20
template <class Alloc>
tuple(allocator_arg_t,
const Alloc& a,
const Types&...); // (16) C++11
template <class Alloc>
EXPLICIT tuple(allocator_arg_t,
const Alloc& a,
const Types&...); // (16) C++17
template <class Alloc>
explicit(see below) constexpr tuple(allocator_arg_t,
const Alloc& a,
const Types&...); // (16) C++20
template <class Alloc, class... UTypes>
tuple(allocator_arg_t,
const Alloc& a,
UTypes&&...); // (17) C++11
template <class Alloc, class... UTypes>
EXPLICIT tuple(allocator_arg_t,
const Alloc& a,
UTypes&&...); // (17) C++17
template <class Alloc, class... UTypes>
explicit(see below) constexpr tuple(allocator_arg_t,
const Alloc& a,
UTypes&&...); // (17) C++20
template <class Alloc>
tuple(allocator_arg_t,
const Alloc& a,
const tuple&); // (18) C++11
template <class Alloc>
constexpr tuple(allocator_arg_t,
const Alloc& a,
const tuple&); // (18) C++20
template <class Alloc>
tuple(allocator_arg_t,
const Alloc& a,
tuple&&); // (19) C++11
template <class Alloc>
constexpr tuple(allocator_arg_t,
const Alloc& a,
tuple&&); // (19) C++20
template<class Alloc, class... UTypes>
explicit(see below) constexpr
tuple(allocator_arg_t,
const Alloc& a,
tuple<UTypes...>&); // (20) C++23
template <class Alloc, class... UTypes>
tuple(allocator_arg_t,
const Alloc& a,
const tuple<UTypes...>&); // (21) C++11
template <class Alloc, class... UTypes>
EXPLICIT tuple(allocator_arg_t,
const Alloc& a,
const tuple<UTypes...>&); // (21) C++17
template <class Alloc, class... UTypes>
explicit(see below) constexpr
tuple(allocator_arg_t,
const Alloc& a,
const tuple<UTypes...>&); // (21) C++20
template <class Alloc, class... UTypes>
tuple(allocator_arg_t,
const Alloc& a,
tuple<UTypes...>&&); // (22) C++11
template <class Alloc, class... UTypes>
EXPLICIT tuple(allocator_arg_t,
const Alloc& a,
tuple<UTypes...>&&); // (22) C++17
template <class Alloc, class... UTypes>
explicit(see below) constexpr
tuple(allocator_arg_t,
const Alloc& a,
tuple<UTypes...>&&); // (22) C++20
template<class Alloc, class... UTypes>
explicit(see below) constexpr
tuple(allocator_arg_t,
const Alloc& a,
const tuple<UTypes...>&&); // (23) C++23
template<class Alloc, class U1, class U2>
explicit(see below) constexpr
tuple(allocator_arg_t,
const Alloc& a,
pair<U1, U2>&); // (24) C++23
template <class Alloc, class U1, class U2>
tuple(allocator_arg_t,
const Alloc& a,
const pair<U1, U2>&); // (25) C++11
template <class Alloc, class U1, class U2>
EXPLICIT tuple(allocator_arg_t,
const Alloc& a,
const pair<U1, U2>&); // (25) C++17
template <class Alloc, class U1, class U2>
explicit(see below) constexpr
tuple(allocator_arg_t,
const Alloc& a,
const pair<U1, U2>&); // (25) C++20
template <class Alloc, class U1, class U2>
tuple(allocator_arg_t,
const Alloc& a,
pair<U1, U2>&&); // (26) C++11
template <class Alloc, class U1, class U2>
EXPLICIT tuple(allocator_arg_t,
const Alloc& a,
pair<U1, U2>&&); // (26) C++17
template <class Alloc, class U1, class U2>
explicit(see below) constexpr
tuple(allocator_arg_t,
const Alloc& a,
pair<U1, U2>&&); // (26) C++20
template<class Alloc, class U1, class U2>
explicit(see below) constexpr
tuple(allocator_arg_t,
const Alloc& a,
const pair<U1, U2>&&); // (27) C++23
template<class Alloc, tuple-like UTuple>
explicit(see below) constexpr
tuple(allocator_arg_t, const Alloc& a, UTuple&&); // (28) C++23
tupleオブジェクトの構築
- (1) : デフォルトコンストラクタ(すべての要素を初期化して構築)
- (2) : 可変テンプレートパラメータの型の値によるコピー構築
- (3) : 可変テンプレートパラメータの型に変換可能な値によるムーブ構築
- (4) : コピーコンストラクタ
- (5) : ムーブコンストラクタ
- (6)-(9) : 変換可能な他の
tuple
オブジェクトから構築- (6), (7), (9) はコピー構築、(8) はムーブ構築される
- (10)-(13) : テンプレートパラメータ数が2の場合、
std::pair
オブジェクトから構築する- (10), (11), (13) はコピー構築、(12) はムーブ構築される
- (14) :
tuple-like
なオブジェクトから構築する
以下 (15)-(28) は (1)-(14) のアロケータ指定版であり、アロケータを指定する事以外は (1)-(14) と等価である。
- (15) : アロケータを指定してデフォルト構築する
- (16) : アロケータを指定して可変テンプレートパラメータの型の値によってコピー構築する
- (17) : アロケータを指定して可変テンプレートパラメータの型の値によってムーブ構築する
- (18) : アロケータを指定してコピー構築
- (19) : アロケータを指定してムーブ構築
- (20)-(23) : アロケータを指定して変換可能な他の
tuple
オブジェクトから構築- (20), (21), (23) はコピー構築、(22) はムーブ構築される
- (24)-(27) : テンプレートパラメータ数が2の場合、アロケータを指定して
std::pair
オブジェクトから構築する- (24), (25), (27) はコピー構築、(26) はムーブ構築される
- (28) : アロケータを指定して
tuple-like
なオブジェクトから構築する
テンプレートパラメータ制約
- (1), (15) :
Types...
の全ての型Ti
について、is_default_constructible<Ti>::value == true
であること
- (2), (16) :
Types...
の全ての型Ti
について、is_copy_constructible<Ti>::value == true
であること
- (3), (17) :
sizeof...(Types) == sizeof...(UTypes)
であること- C++20まで :
Types...
の全ての型Ti
と、UTypes...
の全ての型Ui
について、is_constructible<Ti, Ui&&>::value == true
であること - C++17 :
sizeof...(Types) >= 1
であること - C++23 :
disambiguating-constraint
を次のように定義して、sizeof...(Types) == 1
の時、negation<is_same<remove_cvref_t<U0>, tuple>>
sizeof...(Types) == 2 || sizeof...(Types) == 3
の時、bool_constant<!is_same_v<remove_cvref_t<U0>, allocator_arg_t> || is_same_v<remove_cvref_t<T0>, allocator_arg_t>>
- 以上に該当しなければ、
true_type
- C++23 :
conjunction_v<disambiguating-constraint, is_constructible<Types, UTypes>...>
であること
- (4), (18) :
Types...
の全ての型Ti
について、is_copy_constructible<Ti>::value == true
であること
- (5), (19) :
Types...
の全ての型Ti
について、is_move_constructible<Ti>::value == true
であること
- (6)-(9), (20)-(23) :
I
をパラメータパック0, 1, ..., (sizeof...(Types) - 1)
、FWD(u)
をstatic_cast<decltype(u)>(u)
、sizeof...(Types) == 1
の場合は、Types...
をT
へ、UTypes...
をU
へ展開したと定義して- C++23 :
sizeof...(Types) == sizeof...(UTypes) && (is_constructible_v<Types, decltype(get<I>(FWD(u)))> && ...) == true
であること - C++23 : 更に、
sizeof...(Types) != 1
または、is_convertible_v<decltype(u), T> == false && is_constructible_v<T, decltype(u)> == false && is_same_v<T, U> == false
であること
- (7), (21) :
sizeof...(Types) == sizeof...(UTypes)
であることTypes...
の全ての型Ti
と、UTypes...
の全ての型Ui
について、is_constructible<Ti, const Ui&>::value == true
であること- C++17 :
sizeof(Types...) != 1
であるか、そうでなければTypes...
の先頭をT
、UTypes...
の先頭をU
として、!is_convertible_v<const tuple<U>&, T> && !is_constructible_v<T, const tuple<U>&> && !is_same_v<T, U>
がtrue
であること- コピーコンストラクタとのオーバーロードが成立することを意図している
- C++23 : (6)-(9), (20)-(23) の定義参照
- (8), (22) :
sizeof...(Types) == sizeof...(UTypes)
であることTypes...
の全ての型Ti
と、UTypes...
の全ての型Ui
について、is_constructible<Ti, Ui&&>::value == true
であること- C++17 :
sizeof(Types...) != 1
であるか、そうでなければTypes...
の先頭をT
、UTypes...
の先頭をUとして、!is_convertible_v<tuple<U>, T> && !is_constructible_v<T, tuple<U>> && !is_same_v<T, U>
がtrue
であること- ムーブコンストラクタとのオーバーロードが成立することを意図している
- C++23 : (6)-(9), (20)-(23) の定義参照
- (10)-(13), (24)-(27) :
FWD(u)
をstatic_cast<decltype(u)>(u)
、Types...
の0番目の型をT0
、1番目の型をT1
であるとして、- C++23 :
sizeof...(Types) == 2
であること - C++23 :
is_constructible_v<T0, decltype(get<0>(FWD(u))) == true
であること - C++23 :
is_constructible_v<T1, decltype(get<1>(FWD(u))) == true
であること
- (11), (25) :
Types...
の0番目の型をT0
、1番目の型をT1
であるとするsizeof...(Types) == 2
であることis_constructible<T0, const U1&>::value == true
かつis_constructible<T1, const U2&>::value == true
であること- C++23 : (10)-(13), (24)-(27) の定義参照
- (12), (26) :
Types...
の0番目の型をT0
、1番目の型をT1
であるとするsizeof...(Types) == 2
であることis_constructible<T0, U1&&>::value == true
かつis_constructible<T1, U2&&>::value == true
であること- C++23 : (10)-(13), (24)-(27) の定義参照
- (14), (28) :
- C++23 :
tuple-like<UTuple>
であること - C++23 :
different-from<UTuple, tuple>
であること - C++23 :
remove_cvref_t<UTuple>
がranges::subrange
の特殊化でないこと - C++23 :
sizeof...(Types) == tuple_size_v<remove_cvref_t<UTuple>>
であること - C++23 :
(is_constructible_v<Types, decltype(get<I>(std::forward<UTuple>(u)))> && ...) == true
であること - C++23 :
sizeof...(Types) != 1
であるか、またはTypes...
をT
に展開したとしてis_convertible_v<UTuple, T> == false && is_constructible_v<T, UTuple> == false
であること
- C++23 :
備考
- (1) :
- C++17 :
Types...
のうちいずれかの型が非暗黙にデフォルト構築できる場合、この関数はexplicit
となる
- C++17 :
- (2) :
- C++11からC++14まで : 無条件で
explicit
となる - C++17から :
!conjunction_v<is_convertible<const Types&, Types>...>
である場合、この関数はexplicit
となる
- C++11からC++14まで : 無条件で
- (3) :
- C++11からC++14まで : 無条件で
explicit
となる - C++17から :
!conjunction_v<is_convertible<UTypes, Types>...>
である場合、この関数はexplicit
となる - C++23から :
(reference_constructs_from_temporary_v<Types, UTypes&&> || ...)
である場合、この関数は削除定義される
- C++11からC++14まで : 無条件で
- (6)-(9) :
I
をパラメータパック0, 1, ..., (sizeof...(Types) - 1)
、FWD(u)
をstatic_cast<decltype(u)>(u)
と定義して、- C++23 :
!(is_convertible_v<decltype(get<I>(FWD(u))), Types> && ...)
である場合、この関数はexplicit
となる - C++23 :
(reference_constructs_from_temporary_v<Types, decltype(get<I>(FWD(u)))> || ...)
である場合、この関数は削除定義される
- (7) :
- C++17 :
!conjunction_v<is_convertible<const Types&, Types>...>
である場合、この関数はexplicit
となる - C++23 : (6)-(9) の定義参照
- C++17 :
- (8) :
- C++17 :
!conjunction_v<is_convertible<UTypes&&, Types>...>
である場合、この関数はexplicit
となる - C++23 : (6)-(9) の定義参照
- C++17 :
- (10)-(13) :
FWD(u)
をstatic_cast<decltype(u)>(u)
、Types...
の0番目の型をT0
、1番目の型をT1
であるとして、- C++23 :
!is_convertible_v<decltype(get<0>(FWD(u))), T0> ||!is_convertible_v<decltype(get<1>(FWD(u))), T1>
である場合、この関数はexplicit
となる - C++23 :
reference_constructs_from_temporary_v<T0, decltype(get<0>(FWD(u)))> || reference_constructs_from_temporary_v<T1, decltype(get<1>(FWD(u)))>
である場合、この関数は削除定義される
- (11) :
Types...
の0番目の型をT0
、1番目の型をT1
であるとする- C++17 :
!is_convertible_v<const U1&, T0> || !is_convertible_v<const U2&, T1>
である場合、この関数はexplicit
となる - C++23 : (10)-(13) の定義参照
- (12) :
Types...
の0番目の型をT0
、1番目の型をT1
であるとする- C++17 :
!is_convertible_v<U1&&, T0> || !is_convertible_v<U2&&, T1>
である場合、この関数はexplicit
となる - C++23 : (10)-(13) の定義参照
- (14) :
I
をパラメータパック0, 1, ..., (sizeof...(Types) - 1)
と定義して、- C++23 :
!(is_convertible_v<decltype(get<I>(std::forward<UTuple>(u))), Types> && ...)
である場合、この関数はexplicit
となる
- (15) :
- C++20 : 対応するコンストラクタ (1) と同じ条件で
explicit
となる
- C++20 : 対応するコンストラクタ (1) と同じ条件で
- (16) :
- C++17 : 対応するコンストラクタ (2) と同じ条件で
explicit
となる
- C++17 : 対応するコンストラクタ (2) と同じ条件で
- (17) :
- C++17 : 対応するコンストラクタ (3) と同じ条件で
explicit
となる - C++23 : 対応するコンストラクタ (3) と同じ条件で削除定義される
- C++17 : 対応するコンストラクタ (3) と同じ条件で
- (20), (23) :
- C++23 : それぞれ対応するコンストラクタ (6), (9) と同じ条件で
explicit
となる - C++23 : それぞれ対応するコンストラクタ (6), (9) と同じ条件で削除定義される
- C++23 : それぞれ対応するコンストラクタ (6), (9) と同じ条件で
- (21), (22) :
- C++17 : それぞれ対応するコンストラクタ (7), (8) と同じ条件で
explicit
となる - C++23 : それぞれ対応するコンストラクタ (7), (8) と同じ条件で削除定義される
- C++17 : それぞれ対応するコンストラクタ (7), (8) と同じ条件で
- (24), (27) :
- C++23 : それぞれ対応するコンストラクタ (10), (13) と同じ条件で
explicit
となる - C++23 : それぞれ対応するコンストラクタ (10), (13) と同じ条件で削除定義される
- C++23 : それぞれ対応するコンストラクタ (10), (13) と同じ条件で
- (25), (26) :
- C++17 : それぞれ対応するコンストラクタ (11), (12) と同じ条件で
explicit
となる - C++23 : それぞれ対応するコンストラクタ (11), (12) と同じ条件で削除定義される
- C++17 : それぞれ対応するコンストラクタ (11), (12) と同じ条件で
-
(28) :
- C++23 : それぞれ対応するコンストラクタ (14) と同じ条件で
explicit
となる
- C++23 : それぞれ対応するコンストラクタ (14) と同じ条件で
-
C++17では、コンストラクタの各オーバーロードが条件付きで
explicit
となるよう規定された。これは、以下のような初期化子リストを使用したC++17での初期化が不適格になっていたため、適格になるようにするための変更である:
std::tuple<int, int> pixel_coordinates() { return {10, -15}; // C++14でコンパイルエラー! } struct NonCopyable { NonCopyable(int); NonCopyable(const NonCopyable&) = delete; }; std::pair<NonCopyable, double> pmd{42, 3.14}; // C++14でコンパイルエラー!
- この変更はC++17に対するものであるが、コンパイラが早期に対応していたため、一部処理系ではC++14の段階から適格となっていた
-
C++23 では、ダングリング参照の作成が簡単にできていた状態を改善するべく、
reference_constructs_from_temporary
が追加され、ダングリング参照が作成される場合には不適格とするようになった :
// コンストラクタ引数で std::string が構築され // その一時オブジェクトが束縛されるため、ダングリング参照となっていた // C++23 からは不適格であり、コンパイルエラー等で未然に防がれる std::tuple<const std::string&, const std::string&> x("hello", "world");
例
#include <tuple>
#include <string>
#include <utility>
int main()
{
// デフォルト構築
std::tuple<int, char, std::string> t1;
// コピー構築
std::tuple<int, char, std::string> t2(t1);
// ムーブ構築
std::tuple<int, char, std::string> t3(std::move(t2));
// 値を指定して構築
std::tuple<int, char, std::string> t4(1, 'a', "hello");
// pairから構築(2要素の場合のみ)
std::tuple<int, char> t5 = std::make_pair(1, 'a');
// アロケータを指定して構築。
// std::allocator_argを第1引数にすると、第2引数がアロケータと見なされ、
// 第3引数以降がtupleの要素となる
std::tuple<int, char, std::string> t6(std::allocator_arg,
std::allocator<std::tuple<int, char, std::string>>(),
1, 'a', "hello");
}
出力
バージョン
言語
- C++11
処理系
- Clang:
- GCC: 4.7.0 ✅
- ICC:
- Visual C++:
関連項目
参照
- N3471 Constexpr Library Additions: utilities, v3
- N4387 Improving Pair and Tuple (Revision 3)
- C++17での条件付き
explicit
の導入
- C++17での条件付き
- LWG Issue 2549. Tuple EXPLICIT constructor templates that take tuple parameters end up taking references to temporaries and will create dangling references
- P1032R1 Misc constexpr bits
- P0892R2
explicit(bool)
- C++20での
explicit(bool)
構文への対応
- C++20での
- P2165R4 Compatibility between
tuple
,pair
and tuple-like objectstuple-like
なオブジェクトからの構築
- P2255R2 A type trait to detect reference binding to temporary
- 参照型を要素に持つ場合にダングリング参照が容易に作成できていたのを不適格にする
- LWG 3121 tuple constructor constraints for UTypes&&... overloads
- C++23 での (3) のコンストラクタの制約の変更(
disambiguating-constraint
等)について
- C++23 での (3) のコンストラクタの制約の変更(
- P2321R2
zip