Namespaces
Variants

std::ranges::to

cppreference.net에서
 
 
범위 라이브러리
범위 어댑터
 
헤더 <ranges>
template< class C, ranges::input_range R, class... Args >
    requires (!ranges::view<C>)
constexpr C to( R&& r, Args&&... args );
에 정의됨 (1) (C++23부터)
template< template< class... > class C,
          ranges::input_range R, class... Args >
constexpr auto to( R&& r, Args&&... args );
(2) (C++23부터)
template< class C, class... Args >
    requires (!ranges::view<C>)
constexpr /*range adaptor closure*/ to( Args&&... args );
(3) (C++23부터)
template< template< class... > class C, class... Args >
constexpr /*range adaptor closure*/ to( Args&&... args );
(4) (C++23부터)
도우미 템플릿
template< class Container >
constexpr bool /*reservable-container*/ =
    ranges::sized_range<Container> &&
    requires (Container& c, ranges::range_size_t<Container> n)
    {
        c.reserve(n);
        { c.capacity() } -> std::same_as<decltype(n)>;
        { c.max_size() } -> std::same_as<decltype(n)>;
    };
(5) (설명 전용*)
template< class Container, class Reference >
constexpr bool /*container-appendable*/ =
    requires (Container& c, Reference&& ref)
    {
        requires
        (
            requires { c.emplace_back(std::forward<Reference>(ref)); }     ||
            requires { c.push_back(std::forward<Reference>(ref)); }        ||
            requires { c.emplace(c.end(), std::forward<Reference>(ref)); } ||
            requires { c.insert(c.end(), std::forward<Reference>(ref)); }
        );
    };
(6) (설명 전용*)
template< class Reference, class C >
constexpr auto /*container-appender*/( C& c );
(7) (설명 전용*)
template< class R, class T >
concept /*container-compatible-range*/ =
    ranges::input_range<R> &&
    std::convertible_to<ranges::range_reference_t<R>, T>;
(8) (설명 전용*)

범위 변환 함수의 오버로드는 소스 범위를 첫 번째 인자로 받아, 범위를 받는 생성자, std::from_range_t 태그가 지정된 범위 생성자, 반복자-센티넬 쌍을 받는 생성자를 호출하거나, 인자로 생성된 객체에 소스 범위의 각 요소를 뒤에 삽입하여 새로운 비뷰 객체를 생성합니다.

1) 다음과 같이 C의 요소로부터 r 타입의 객체를 생성합니다:
a) 만약 C가 input_range를 만족하지 않거나 std::convertible_to<ranges::range_reference_t<R>, ranges::range_value_t<C>>가 true인 경우:
1) direct-initializing(단, direct-list-initializing은 아님)을 통해, C가 std::forward<R>(r)인 경우 소스 범위 std::forward<Args>(args)...와 나머지 함수 인자들로부터 std::constructible_from<C, R, Args...> 타입의 객체를 생성하는 것처럼 비뷰 객체를 생성합니다.true2)
그렇지 않으면, direct-initializing(단, direct-list-initializing은 아님)을 통해, 가 C인 경우 추가적인 명확성 태그 std::from_range, 소스 범위 std::forward<R>(r) 및 나머지 함수 인자들로부터 std::forward<Args>(args)... 타입의 객체를 생성하는 것처럼 비뷰 객체를 생성합니다.std::constructible_from<C, std::from_range_t, R, Args...>3)true 그렇지 않으면,
direct-initializing(단, direct-list-initializing은 아님)을 통해, 아래 조건이 모두 인 경우 반복자-센티넬 쌍 (반복자가 이고 센티넬이 C이며 반복자와 센티넬이 동일한 타입을 가짐, 즉, 소스 범위는 common_range여야 함) 및 나머지 함수 인자들 ranges::begin(r)로부터 ranges::end(r) 타입의 객체를 생성하는 것처럼 비뷰 객체를 생성합니다: std::forward<Args>(args)...만약 true가 유효하고
  • ranges::common_range<R>
  • 를 만족하는 타입을 나타내는 경우std::iterator_traits<ranges::iterator_t<R>>::iterator_category4)std::derived_from<std::input_iterator_tag>
  • std::constructible_from<C, ranges::iterator_t<R>, ranges::sentinel_t<R>, Args...>
그렇지 않으면, direct-initializing(단, direct-list-initializing은 아님)을 통해, 나머지 함수 인자들 로부터 C 타입의 객체를 생성하는 것처럼 비뷰 범위 객체를 생성한 후 아래와 동등한 호출을 수행합니다: std::forward<Args>(args)...(C++26까지)

if constexpr (ranges::sized_range<R> && /*reservable-container*/<C>)
    c.reserve(static_cast<ranges::range_size_t<C>>(ranges::size(r)));
ranges::for_each(r, /*container-appender*/(c));

(C++26부터)

if constexpr (ranges::approximately_sized_range<R>
            && /*reservable-container*/<C>)
    c.reserve(static_cast<ranges::range_size_t<C>>(ranges::reserve_hint(r)));
ranges::for_each(r, /*container-appender*/(c));

만약

가 Rsized_range(C++26까지)approximately_sized_range(C++26부터)를 만족하고 가 C를 만족하면, 생성된 reservable-container 타입의 객체 c는 초기 저장소 크기 C(C++26까지)ranges::size(r)(C++26부터)ranges::reserve_hint(r)로 저장 공간을 미리 할당하여 새 요소를 삽입하는 동안 추가 할당을 방지할 수 있습니다. 의 각 요소는 r에 추가됩니다. c위 연산들은 아래 두 조건이 모두

인 경우 유효합니다: trueb)

그렇지 않으면, 반환 표현식은 다음과 동등합니다: 이는
to<C>(ranges::ref_view(r) | views::transform([](auto&& elem)
{
    return to<ranges::range_value_t<C>>(std::forward<decltype(elem)>(elem));
}), std::forward<Args>(args)...)

가 ranges::input_range<ranges::range_reference_t<C>>인 경우 범위 내에서 중첩된 범위 생성을 허용합니다. true 그렇지 않으면 프로그램은 ill-formed입니다.

2)
의 요소로부터 추론된 타입의 객체를 생성합니다. r

를 /*input-iterator*/LegacyInputIterator를 만족하는 설명 전용 타입이라고 합시다: (

struct /*input-iterator*/
{
    using iterator_category = std::input_iterator_tag;
    using value_type = ranges::range_value_t<R>;
    using difference_type = std::ptrdiff_t;
    using pointer = std::add_pointer_t<ranges::range_reference_t<R>>;
    using reference = ranges::range_reference_t<R>;
    reference operator*() const;                      // not defined
    pointer operator->() const;                       // not defined
    /*input-iterator*/& operator++();                 // not defined
    /*input-iterator*/ operator++(int);               // not defined
    bool operator==(const /*input-iterator*/&) const; // not defined
};
설명 전용*)

를 다음과 같이 정의합시다: /*DEDUCE-EXPR*/, 해당 표현식이 유효한 경우.

  • C(std::declval<R>(), std::declval<Args>()...)그렇지 않으면,
  • , 해당 표현식이 유효한 경우.
C(std::from_range, std::declval<R>(),
  std::declval<Args>()...)
그렇지 않으면,
  • , 해당 표현식이 유효한 경우.
C(std::declval</*input-iterator*/>(),
  std::declval</*input-iterator*/>(),
  std::declval<Args>()...)
그렇지 않으면 프로그램은 ill-formed입니다.
  • 호출은 다음과 동등합니다:

.

to<decltype(/*DEDUCE-EXPR*/)>
  (std::forward<R>(r), std::forward<Args>(args)...)
3,4)
를 만족하고 예약 가능한 경우 true입니다.ranges::sized_range6)
타입의 한 요소가 멤버 함수 호출 true, Reference, Container 또는 emplace_back를 통해 push_back에 추가될 수 있는 경우 emplace입니다.insert7)
반환된 함수 객체에 대한 호출이 컨테이너에 한 요소를 추가하는 것과 표현식-동등한 함수 객체를 반환합니다. 반환 표현식은 와 동등합니다.
return [&c]<class Reference>(Reference&& ref)
{
    if constexpr (requires { c.emplace_back(std::declval<Reference>()); })
        c.emplace_back(std::forward<Reference>(ref));
    else if constexpr (requires { c.push_back(std::declval<Reference>()); })
        c.push_back(std::forward<Reference>(ref));
    else if constexpr (requires { c.emplace(c.end(),
                                            std::declval<Reference>()); })
        c.emplace(c.end(), std::forward<Reference>(ref));
    else
        c.insert(c.end(), std::forward<Reference>(ref));
};
8) 해당 범위 참조 타입이 R로 변환 가능해야 하는 입력 범위 T를 생성하는 컨테이너의 정의에 사용됩니다.

매개변수

r - 소스 범위 객체
args - 범위를 구성하기 위한 인수 목록 ( 1,2 ) 또는 범위 어댑터 클로저 객체의 마지막 매개변수에 바인딩할 인수 목록 ( 3,4 )
타입 요구사항
-
C 는 cv-unqualified 클래스 타입이어야 함 ( 1,3 )

반환값

1,2) 생성된 비-뷰 객체.
3,4) 지정되지 않은 타입의 범위 어댑터 클로저 객체로, 다음 속성들을 가집니다:

ranges::to 반환 타입

멤버 객체

반환된 객체는 대상 객체가 없는 것처럼 동작하며, std::tuple 객체 tup 이 std:: tuple < std:: decay_t < Args > ... > ( std:: forward < Args > ( args ) ... ) 로 생성된 것과 같습니다. 단, 반환된 객체의 할당 동작은 지정되지 않으며 이름들은 설명 목적으로만 사용됩니다.

생성자

ranges::to ( 3,4 ) 의 반환 타입은 복사/이동 생성자가 멤버별 복사/이동을 수행하는 것처럼 동작합니다. 이 타입은 모든 멤버 객체(위에서 명시된)가 CopyConstructible 인 경우 CopyConstructible 이며, 그렇지 않은 경우 MoveConstructible 입니다.

멤버 함수 operator()

이전 호출 range :: to < /* see below */ > ( args... ) 로부터 얻은 객체 G 에 대해, glvalue g 가 G 를 지정할 때 함수 호출 표현식 g ( r ) 에서 호출되면, 저장된 객체의 호출이 다음과 같이 발생합니다:

  • ranges :: to < /* see below */ > ( r, std :: get < Ns > ( g. tup ) ... ) , 여기서
  • r 는 input_range 를 만족해야 하는 소스 범위 객체입니다.
  • Ns 는 정수 팩 0 , 1 , ..., ( sizeof... ( Args ) - 1 ) 입니다.
  • g 는 호출 표현식에서 lvalue인 경우 lvalue이고, 그렇지 않으면 rvalue입니다. 따라서 std :: move ( g ) ( r ) 는 바인딩된 인수들을 호출로 이동할 수 있으며, g ( r ) 는 복사합니다.
  • 지정된 템플릿 인수는 ( 3 ) C 이거나 ( 4 ) view 를 만족하지 않아야 하는 클래스 템플릿 C 에서 추론된 타입입니다.

g 가 volatile 한정 타입을 가지는 경우 프로그램의 형식이 올바르지 않습니다.

예외

비-뷰 객체의 생성이 예외를 던질 때만 예외를 던집니다.

참고 사항

컨테이너에 요소를 삽입하는 작업은 복사가 포함될 수 있으며, 이는 간접 호출 과정에서 lvalue 참조가 생성되기 때문에 이동보다 효율이 낮을 수 있습니다. 사용자는 views:: as_rvalue 를 사용하여 범위를 적응시켜 요소들이 간접 호출 과정에서 항상 rvalue 참조를 생성하도록 선택할 수 있으며, 이는 이동을 의미합니다.

파이프 구문을 사용할 때 괄호는 필수입니다.

auto vec = r | std::ranges::to<std::vector>;   // 오류
auto vec = r | std::ranges::to<std::vector>(); // 정상
기능 테스트 매크로 값 표준 기능
__cpp_lib_ranges_to_container 202202L (C++23) std::ranges::to
__cpp_lib_ranges_reserve_hint 202502L (C++26) ranges::approximately_sized_range , ranges::reserve_hint , 및 변경사항 to std::ranges::to

예제

미리보기 링크: Compiler Explorer

#include <boost/container/devector.hpp>
#include <concepts>
#include <initializer_list>
#include <list>
#include <print>
#include <ranges>
#include <regex>
#include <string>
#include <vector>

int main()
{
    auto vec = std::views::iota(1, 5)
             | std::views::transform([](int v){ return v * 2; })
             | std::ranges::to<std::vector>();

    static_assert(std::same_as<decltype(vec), std::vector<int>>);
    std::println("1) {}", vec);

    auto list = vec | std::views::take(3) | std::ranges::to<std::list<double>>();
    std::println("2) {}", list);
}

void ctor_demos()
{
    // 1.a.1) Direct init
    {
        char array[]{'a', 'b', '\0', 'c'};

        // Argument type is convertible to result value type:
        auto str_to = std::ranges::to<std::string>(array);
        // Equivalent to
        std::string str(array);

        // Result type is not an input range:
        auto re_to = std::ranges::to<std::regex>(array);
        // Equivalent to
        std::regex re(array);
    }

    // 1.a.2) from_range ctor
    {
        auto list = {'a', 'b', '\0', 'c'};

        // Argument type is convertible to result value type:
        auto str_to = std::ranges::to<std::string>(list);
        // Equivalent to
        // std::string str(std::from_range, list);

        // Result type is not an input range:
        [[maybe_unused]]
        auto pair_to = std::ranges::to<std::pair<std::from_range_t, bool>>(true);
        // Equivalent to
        std::pair<std::from_range_t, bool> pair(std::from_range, true);
    }

    // 1.a.3) iterator pair ctor
    {
        auto list = {'a', 'b', '\0', 'c'};

        // Argument type is convertible to result value type:
        auto devector_to = std::ranges::to<boost::container::devector<char>>(list);
        // Equivalent to
        boost::container::devector<char> devector(std::ranges::begin(list),
                                                  std::ranges::end(list));

        // Result type is not an input range:
        std::regex re;
        auto it_to = std::ranges::to<std::cregex_iterator>(list, re);
        // Equivalent to
        std::cregex_iterator it(std::ranges::begin(list), std::ranges::end(list), re);
    }
}

출력:

1) [2, 4, 6, 8]
2) [2, 4, 6]

결함 보고서

다음 동작 변경 결함 보고서는 이전에 발표된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 수정된 동작
LWG 3984 C++23 ranges::to 의 중첩 생성 브랜치에서
R& 가 viewable_range 를
모델링하지 않을 경우 프로그램이 비정형
정형화됨
LWG 4016 C++23 ranges::to 의 컨테이너 삽입 브랜치에서
삽입 반복자 사용이 포함됨
컨테이너에 요소를 직접 추가하는
방식으로 대체됨

참조문헌

  • C++23 표준 (ISO/IEC 14882:2024):
  • 26.5.7 범위 변환 [range.utility.conv]