最終更新日時(UTC):
が更新

履歴 編集

function
<utility>

std::pair::コンストラクタ

pair();                                                       // (1) C++03
constexpr pair();                                             // (1) C++11
EXPLICIT constexpr pair();                                    // (1) C++17
explicit(see below) constexpr pair();                         // (1) C++20

pair(const pair&) = default;                                  // (2)
pair(pair&&) = default;                                       // (3) C++11

pair(const T1& x, const T2& y);                               // (4) C++03
constexpr pair(const T1& x, const T2& y);                     // (4) C++14
EXPLICIT constexpr pair(const T1& x, const T2& y);            // (4) C++17
explicit(see below) constexpr pair(const T1& x, const T2& y); // (4) C++20

template <class U, class V>
pair(U&& x, V&& y);                                           // (5) C++11
template <class U, class V>
constexpr pair(U&& x, V&& y);                                 // (5) C++14
template <class U, class V>
EXPLICIT constexpr pair(U&& x, V&& y);                        // (5) C++17
template <class U, class V>
explicit(see below) constexpr pair(U&& x, V&& y);             // (5) C++20
template <class U = T1, class V = T2>
explicit(see below) constexpr pair(U&& x, V&& y);             // (5) C++23

template<class U, class V>
explicit(see below) constexpr pair(pair<U, V>& p);            // (6) C++23

template <class U, class V>
pair(const pair<U, V>& p);                                    // (7) C++03
template <class U, class V>
constexpr pair(const pair<U, V>& p);                          // (7) C++14
template <class U, class V>
EXPLICIT constexpr pair(const pair<U, V>& p);                 // (7) C++17
template <class U, class V>
explicit(see below) constexpr pair(const pair<U, V>& p);      // (7) C++20

template <class U, class V>
pair(pair<U, V>&& p);                                         // (8) C++11
template <class U, class V>
constexpr pair(pair<U, V>&& p);                               // (8) C++14
template <class U, class V>
EXPLICIT constexpr pair(pair<U, V>&& p);                      // (8) C++17
template <class U, class V>
explicit(see below) constexpr pair(pair<U, V>&& p);           // (8) C++20

template<class U, class V>
explicit(see below) constexpr pair(const pair<U, V>&& p);     // (9) C++23

template<pair-like P>
explicit(see below) constexpr pair(P&& p);                    // (10) C++23

template <class... Args1, class... Args2>
pair(piecewise_construct_t,
     tuple<Args1...> first_args,
     tuple<Args2...> second_args);                            // (11) C++11
template <class... Args1, class... Args2>
constexpr pair(piecewise_construct_t,
               tuple<Args1...> first_args,
               tuple<Args2...> second_args);                  // (11) C++20

概要

pairオブジェクトを構築する。

  • (1) : デフォルトコンストラクタ(firstsecondを初期化して構築)
  • (2) : コピーコンストラクタ
  • (3) : ムーブコンストラクタ
  • (4) : firstsecondの変換可能な型の値から構築
  • (5) : firstsecondに変換可能な型の値からムーブ構築
  • (6) : 変換可能な他のpairオブジェクトから構築
  • (7) : 変換可能な他のpairオブジェクトから構築
  • (8) : 変換可能な他のpairオブジェクトからムーブ構築
  • (9) : 変換可能な他のpairオブジェクトから構築
  • (10) : pair-likeなオブジェクトから構築
  • (11) : firstsecondのコンストラクタ引数をstd::tupleに詰めて受け取り、first_argssecond_args内のそれぞれの要素を転送してfirstsecondを直接構築
    • 転送は、std::tupleオブジェクト(first_args/second_args)内の要素xとその型UArgs1.../Args2...に含まれる型)によって、std::forward<U>(x)のようにしてコンストラクタに渡される

テンプレートパラメータ制約

  • (1) :
  • (4) :
  • (5) :
    • is_constructible<first_type, U&&>::value && is_constructible<second_type, V&&>::valueであること
    • C++14まで : Ufirst_typeに暗黙変換可能でない場合、もしくはVsecond_typeに暗黙変換可能でない場合、この関数はオーバーロード解決から除外される
  • (6)-(10) :
  • (7) :
    • is_constructible<first_type, const U&>::value && is_constructible<second_type, const V&>::valueであること
    • C++14まで : const U&first_typeに暗黙変換可能でない場合、もしくはconst V&second_typeに暗黙変換可能でない場合、この関数はオーバーロード解決から除外される
    • C++23 : (6)-(10) での定義参照
  • (8) :
    • is_constructible<first_type, U&&>::value && is_constructible<second_type, V&&>::valueであること
    • C++14まで : Ufirst_typeに暗黙変換可能でない場合、もしくはVsecond_typeに暗黙変換可能でない場合、この関数はオーバーロード解決から除外される
    • C++23 : (6)-(10) での定義参照
  • (11) :

delete定義される条件(C++23)

explicitになる条件

  • (1) :
    • C++17 : first_typesecond_typeのどちらかが非暗黙にデフォルト構築できない場合、explicit指定される
  • (4) :
  • (5) :
  • (6)-(10) :
    • FWD(u)static_cast<deccltype(u)>(u)と定義して
    • C++23 : !is_convertible_v<decltype(get<0>(FWD(p))), first_type> || !is_convertible_v<decltype(get<1>(FWD(p))), second_type>である場合、explicit指定される
  • (7) :
    • C++17 : !is_convertible_v<const U1&, first_type> || !is_convertible_v<const U2&, second_type>である場合、explicit指定される
    • C++23 : (6)-(10) での定義参照(複雑であるが、条件は同等である)
  • (8) :
    • C++17 : !is_convertible_v<U1, first_type> || !is_convertible_v<U2, second_type>である場合、explicit指定される
    • C++23 : (6)-(10) での定義参照(複雑であるが、条件は同等である)

備考

  • (11)のコンストラクタではfirst/secondをそのコンストラクタ引数から直接構築するため、コピーもムーブもできないような型でも初期化することができる

  • 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::pair<const std::string&, const std::string&> x("hello", "world");
    

#include <iostream>
#include <utility>
#include <string>
#include <tuple> // std::make_tuple

template <class T1, class T2>
void print(const std::string& name, const std::pair<T1, T2>& p)
{
  std::cout << name << " : (" << p.first << "," << p.second << ")" << std::endl;
}

struct X {
  int a, b, c;

  X() : a(0), b(0), c(0) {}
  X(int a, int b, int c) : a(a), b(b), c(c) {}
};

std::ostream& operator<<(std::ostream& os, const X& x)
{
  return os << "X(" << x.a << " " << x.b << " " << x.c << ")";
}

struct Y {
  int a, b;

  Y() : a(0), b(0) {}
  Y(int a, int b) : a(a), b(b) {}
};

std::ostream& operator<<(std::ostream& os, const Y& y)
{
  return os << "Y(" << y.a << " " << y.b << ")";
}

int main()
{
  // (1) デフォルト構築
  {
    constexpr std::pair<int, double> p1;
    print("p1", p1);
  }

  // (2) コピー構築
  {
    std::pair<int, std::string> p(1, "abc");
    std::pair<int, std::string> p2 = p;
     print("p2", p2);
  }

  // (3) ムーブ構築
  {
    std::pair<int, std::string> p(1, "abc");
    std::pair<int, std::string> p3 = std::move(p);
    print("p3", p3);
  }

  // (4) firstとsecondの初期値から構築
  {
    std::pair<int, std::string> p4(1, std::string("abc"));
    print("p4", p4);
  }

  // (5) firstとsecondの右辺値からムーブ構築
  {
    int x = 1;
    std::string s = "abc";
    std::pair<int, std::string> p5(std::move(x), std::move(s));
    print("p5", p5);
  }

  // (7) 変換可能なpairから構築
  {
    std::pair<int, const char*> p(1, "abc");
    std::pair<int, std::string> p6 = p;
    print("p6", p6);
  }

  // (8) 変換可能なpairからムーブ構築
  {
    std::pair<int, const char*> p(1, "abc");
    std::pair<int, std::string> p7 = std::move(p);
    print("p7", p7);
  }

  // (11) first_typeとsecond_typeのコンストラクタ引数から構築
  {
    std::pair<X, Y> p8(std::piecewise_construct,
                       std::make_tuple(1, 2, 3),
                       std::make_tuple(4, 5));
    print("p8", p8);
  }
}

出力

p1 : (0,0)
p2 : (1,abc)
p3 : (1,abc)
p4 : (1,abc)
p5 : (1,abc)
p6 : (1,abc)
p7 : (1,abc)
p8 : (X(1 2 3),Y(4 5))

バージョン

言語

  • C++11 : ムーブ構築とpiecewise構築

処理系

  • Clang: ??
  • GCC: 4.6.1
  • ICC: ??
  • Visual C++: 2010, 2012, 2013, 2015
    • C++03で規定されていたものは、2010より前のバージョンから実装されている。
    • 2010までは、(11) std::piecewise_construct版が実装されていない。
    • 2013までは、デフォルトコンストラクタにconstexprが付与されていない。

関連項目

参照