std::complex(및 사용자 지정 비 POD 유형)에 대한 구조적 바인딩 활성화

13383 단어 cppstl
C++의 아버지인 Bjarne Stroustrup은 A Tour of C++에서 비 POD 유형인 std::complex 과 함께 구조화된 바인딩 선언을 사용할 수 있다고 언급했습니다(데이터 속성을 캡슐화하고 값은 real()imag() 메서드 호출로 가져옴). 오늘부터 실제로 std::complex ( Compiler Explorer 으로 확인)에 대해 작동하지 않으며 WG21 standard working draftstd::complex 의 기능을 언급하지 않습니다. 그러나 다음 규칙을 통합하여 std::complex 을 튜플과 같은 유형으로 만들어서 작동하도록 할 수 있습니다( structured binding 참조).
  • std::tuple_size<std::complex<T>>::value은 구조화된 바인딩,
  • 의 일부인 식별자의 수를 나타내는 정수 상수 표현식이어야 합니다.
  • 각 식별자에 대한 식 std::tuple_element<i, std::complex<T>>::type , 여기서 i 은 상수 식 식별자 색인이며 식별자 유형
  • 이어야 합니다.
  • 각 식별자에 대해 get<i>(c) 함수(여기서 i은 상수 식 식별자 인덱스이고 c은 복합 개체임)는 식별자 값을 제공해야 합니다.
  • std 네임스페이스를 확장하고 모든 구성 요소를 제공하기만 하면 됩니다.

    namespace std {
        template<typename T>
        class tuple_size<complex<T>> {
        public:
            static constexpr size_t value = 2;
        };
        template<size_t I, typename T>
        auto get(const complex<T>& c) {
            if constexpr (I == 0) return c.real();
            else return c.imag();
        }
        template <size_t I, typename T>
        class tuple_element<I, complex<T>> {
        public:
            using type = decltype(get<I>(declval<complex<T>>()));
        };
    }
    


    이제 이것은 잘 작동합니다.

    auto c = std::complex<int>{1,1};
    auto [r, i] = c + 2;
    


    마찬가지로 사용자 정의 유형의 경우:

    template <typename X, typename Y>
    class NonPOD {
        X x;
        Y y;
    public:
        NonPOD(X x, Y y): x{x}, y{y} {}
        X getX() const { return x; }
        Y getY() const { return y; }
    };
    
    namespace std {
    template <size_t I, typename Arg, typename ...Args>
    class type_alternatives {
    public:
        using type = typename type_alternatives<I-1, Args...>::type;
    };
    
    template <typename Arg, typename ...Args>
    class type_alternatives<0, Arg, Args...> {
    public:
        using type = Arg;
    };
    
    template <size_t I, typename X, typename Y>
    class tuple_element<I, NonPOD<X, Y>> {
    public:
        using type = typename type_alternatives<I, X, Y>::type;
    };
    } // namespace std
    
    template <size_t I, typename X, typename Y>
    typename std::tuple_element<I, NonPOD<X, Y>>::type
    get(const NonPOD<X, Y>& t) {
        if constexpr (I == 0) return t.getX();
        else return t.getY();
    }
    
    auto test() {
     auto sb = NonPOD{1, 2.};
     auto [s, b] = sb;
     return s+b;
    }
    


    자체 유형에서 독립 실행형 get<i>() 대신 멤버 get<i>(obj) 메서드를 정의할 수 있습니다.

    참고: std::complex에는 흥미로운 속성이 있습니다.

    4
    If z is an lvalue of type cv complex then:

    (4.1)
    the expression reinterpret_cast(z) is well-formed,

    (4.2)
    reinterpret_cast(z)[0] designates the real part of z, and

    (4.3)
    reinterpret_cast(z)[1] designates the imaginary part of z.



    즉, 다음과 같이 간단하게 캐스팅할 수 있습니다.

    auto c = std::complex<int>{1,1};
    auto [r, i] = reinterpret_cast<int(&)[2]>(c);
    


    그래도 임시로 사용하지 않는 것이 좋습니다.

    좋은 웹페이지 즐겨찾기