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

履歴 編集

customization point object
<concepts>

std::ranges::swap(C++20)

namespace std::ranges {
  inline namespace /*unspecified*/ {

    inline constexpr /*unspecified*/ swap = /*unspecified*/;
  }
}

概要

ranges::swapは2つの引数を受け取り、それらの値の交換を行う関数オブジェクトである。

効果

std::ranges::swap(a, b)のように呼び出された時、以下のいずれかと等価(上から順に考慮される)

  1. 引数a, bの型がクラス型であるか列挙型であり、std::ranges::swap(本関数オブジェクト)の宣言を含まず下記のswap関数宣言を含むコンテキストで、void(swap(a, b))が呼び出し可能ならばvoid(swap(a, b))

    template<class T>
    void swap(T&, T&) = delete;
    

  2. a, bが共に同じ長さの配列型の左辺値であり、ranges::swap(*a, *b)が呼び出し可能ならばranges::swap_ranges(a, b)

    • 1か3に委譲して要素毎にswapされる
  3. a, bが共に同じ型Tの左辺値であり、TT&move_constructible<T>及びassignable_from<T&, T>のモデルとなる場合、std::swap()相当の操作によってa, bの値を交換する。

  4. それ以外の場合、呼び出しは不適格

戻り値

何も返さない。
std::ranges::swap(a, b)の呼び出しが有効であるならば、常に戻り値型はvoidとなる。

例外

上記「効果」節のそれぞれのケース毎に

  1. 呼び出されるswap(a, b)(及び、もし返されるのならば戻り値のデストラクタ)が例外を送出するかに従う
  2. noexcept(ranges::swap(*a, *b))が指定される
  3. noexcept(is_nothrow_move_constructible_v<T> && is_nothrow_move_assignable_v<T>)が指定される

定数式に評価される条件

上記「効果」節のそれぞれのケース毎に

  1. 呼び出されるswap(a, b)(及び、もし返されるのならば戻り値のデストラクタ)が定数評価可能であるかに従う。
  2. a, bの要素型によって、1か3に従う
  3. 以下の条件を全て満たす場合に定数評価可能
    • Tはリテラル型である
    • a = std::move(b), b = std::move(a)は共に定数評価可能
    • 次のような初期化式が定数評価可能
      T t1(std::move(a));
      T t2(std::move(b));
      

カスタマイゼーションポイント

上記「効果」節1のケースでは、ユーザー定義swap()を定義しておくことによって実行される交換操作をカスタマイズすることができる。

  1. a, bのどちらかの型と同じ名前空間で、もしくはHidden friendsとして、a, bの型のペアについて呼び出し可能なswap()を定義しておく
  2. その要素型について、1にアダプトしておく
  3. --

備考

上記「効果」節1の場合に、呼び出されたswap()関数が実際には交換操作を行わない場合はプログラムは不適格。ただし、その診断は要求されていない(未定義動作となりえる)。

#include <iostream>
#include <concepts>

namespace NS {
  struct swappable1 {
    int n = 0;

    swappable1(int m) : n(m) {}

    swappable1(swappable1&&) = delete;
  };

  // 非メンバ関数として定義
  void swap(swappable1& lhs, swappable1& rhs) {
    std::swap(lhs.n, rhs.n);
  }


  struct swappable2 {
    double d = 0.0;

    swappable2(double v) : d(v) {}

    swappable2(swappable2&&) = delete;

    // Hidden friendsな関数として定義
    friend void swap(swappable2& lhs, swappable2& rhs) {
      std::swap(lhs.d, rhs.d);
    }
  };
}

int main() {
  {
    int a = 5, b = 7;
    std::ranges::swap(a, b);

    std::cout << "a = " << a << ", b = " << b << std::endl;
  }
  std::cout << "\n";
  {
    NS::swappable1 a{11}, b{13};
    std::ranges::swap(a, b);

    std::cout << "a = " << a.n << ", b = " << b.n << std::endl;
  }
  std::cout << "\n";
  {
    NS::swappable2 a{3.14}, b{2.71};
    std::ranges::swap(a, b);

    std::cout << "a = " << a.d << ", b = " << b.d << std::endl;
  }
  std::cout << "\n";
  {
    int a[] = {1, 3, 5, 7}, b[] = {0, 2, 4, 6};
    std::ranges::swap(a, b);

    std::cout << "a = {";
    for (int n : a) std::cout << n << ", ";
    std::cout << "}, b = {";
    for (int n : b) std::cout << n << ", ";
    std::cout << "}";
  }
}

出力

a = 7, b = 5

a = 13, b = 11

a = 2.71, b = 3.14

a = {0, 2, 4, 6, }, b = {1, 3, 5, 7, }

バージョン

言語

  • C++20

処理系

関連項目

参照