• Class / Function / Type

      std::
    • Header file

      <>
    • Other / All

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

    履歴 編集

    concept
    <concepts>

    std::swappable

    namespace std {
      template<class T>
      concept swappable = requires(T& a, T& b) { ranges::swap(a, b); };
    
      template<class T, class U>
      concept swappable_with =
        common_reference_with<T, U> &&
        requires(T&& t, U&& u) {
          ranges::swap(std::forward<T>(t), std::forward<T>(t));
          ranges::swap(std::forward<U>(u), std::forward<U>(u));
          ranges::swap(std::forward<T>(t), std::forward<U>(u));
          ranges::swap(std::forward<U>(u), std::forward<T>(t));
        };
    }
    

    概要

    swappable及びswappable_withは、指定された型TもしくはT, Uのオブジェクト間で、その値の交換操作(swap操作)が可能であることを表すコンセプトである。

    swappable

    #include <iostream>
    #include <concepts>
    
    template<typename T>
    requires std::swappable<T>
    void f(const char* name) {
      std::cout << name << " is swappable" << std::endl;
    }
    
    template<typename T>
    void f(const char* name) {
      std::cout << name << " is not swappable" << std::endl;
    }
    
    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);
        }
      };
    }
    
    struct not_swappable {
      not_swappable(not_swappable&&) = delete;
      not_swappable& operator==(not_swappable&&) = delete;
    };
    
    int main() {
      f<int>("int");
      f<int&&>("int&&");
      f<NS::swappable1>("NS::swappable1");
      f<NS::swappable2>("NS::swappable2");
      f<int[5]>("int[5]");
    
      std::cout << "\n";
    
      f<const int>("const int");
      f<not_swappable>("not_swappable");
    }
    

    出力

    int is swappable
    int&& is swappable
    NS::swappable1 is swappable
    NS::swappable2 is swappable
    int[5] is swappable
    
    const int is not swappable
    not_swappable is not swappable
    

    swappable_with

    #include <iostream>
    #include <concepts>
    
    template<typename T, typename U>
    requires std::swappable_with<T, U>
    void f(const char* name, const char* name2) {
      std::cout << name << " is swappable with " << name2 << std::endl;
    }
    
    template<typename T, typename U>
    void f(const char* name, const char* name2) {
      std::cout << name << " is not swappable with " << name2 << std::endl;
    }
    
    namespace NS {
    
      struct S1 {
        std::size_t n = 0;
    
        operator std::size_t() const {
          return this->n;
        }
    
        //swappable_withであるためには、自身がswappableである必要がある
        friend void swap(S1& a, S1& b) {
          std::swap(a.n, b.n);
        }
      };
    
      struct S2 {
        std::size_t s = 0;
    
        operator std::size_t() const {
          return this->s;
        }
    
        //swappable_withであるためには、自身がswappableである必要がある
        friend void swap(S2& a, S2& b) {
          std::swap(a.s, b.s);
        }
      };
    
      void swap(S1& s1, S2& s2) {
        std::swap(s1.n, s2.s);
      }
    
      //引数順を逆にしたものも必要
      void swap(S2& s2, S1& s1) {
        swap(s1, s2);
      }
    }
    
    //std::common_referenceおよびstd::common_reference_withにアダプトする
    namespace std {
      template<template<class> class TQual, template<class> class UQual>
      struct basic_common_reference<NS::S1, NS::S2, TQual, UQual> {
        using type = const std::size_t&;
      };
    
      //対称性のために引数順を逆にしたものも定義する
      template<template<class> class TQual, template<class> class UQual>
      struct basic_common_reference<NS::S2, NS::S1, TQual, UQual> {
        using type = const std::size_t&;
      };
    }
    
    int main() {
      f<NS::S1&, NS::S2&>("NS::S1&", "NS::S2&");
      f<NS::S2&, NS::S1&>("NS::S2&", "NS::S1&");
    
      //右辺値参照バージョンを用意してないので、参照修飾なしだとswappable_withとならない
      f<NS::S1, NS::S2>("NS::S1", "NS::S2");
      f<NS::S2, NS::S1>("NS::S2", "NS::S1");
    }
    

    出力

    NS::S1& is swappable with NS::S2&
    NS::S2& is swappable with NS::S1&
    NS::S1 is not swappable with NS::S2
    NS::S2 is not swappable with NS::S1
    

    バージョン

    言語

    • C++20

    処理系

    関連項目

    参照