Namespaces
Variants

std::ranges:: to

From cppreference.net
Ranges library
Range adaptors
헤더에 정의됨 <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 /*범위 어댑터 클로저*/ 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) 다음에서 r 의 요소들로 C 타입의 객체를 생성합니다:
a) 만약 C input_range 를 만족하지 않거나 std:: convertible_to < ranges:: range_reference_t < R > , ranges:: range_value_t < C >> true 인 경우:
1) 비-뷰 객체를 마치 직접 초기화 (단 직접 목록 초기화는 제외)하는 것처럼 구성하며, 소스 범위 std:: forward < R > ( r ) 와 나머지 함수 인자들 std:: forward < Args > ( args ) ... 를 사용하여 타입 C 의 객체를 초기화합니다. 단, std:: constructible_from < C, R, Args... > true 인 경우에만 적용됩니다.
2) 그렇지 않으면, 추가적인 분별 태그 std:: from_range , 소스 범위 std:: forward < R > ( r ) 및 나머지 함수 인자들 std:: forward < Args > ( args ) ... 를 사용하여 C 타입의 객체를 직접 초기화 (단 직접 목록 초기화는 제외)하는 것처럼 비-뷰 객체를 구성합니다. 단, std:: constructible_from < C, std:: from_range_t , R, Args... > true 인 경우에만 적용됩니다.
3) 그렇지 않으면, 비-뷰 객체를 마치 직접 초기화(direct-initializing) (단 직접 목록 초기화(direct-list-initializing)는 아님)하듯이 생성합니다. 이때 C 타입의 객체를 반복자-감시자 쌍( ranges:: begin ( r ) 를 반복자로, ranges:: end ( r ) 를 감시자로 사용)에서 생성하며, 반복자와 감시자는 동일한 타입을 가져야 합니다(즉, 소스 범위는 공통 범위(common range)여야 합니다). 그리고 다음의 모든 조건이 true 인 경우 나머지 함수 인수 std:: forward < Args > ( args ) ... 를 사용합니다:
4) 그렇지 않으면, 비-뷰 범위 객체를 마치 직접 초기화 (단, 직접 목록 초기화는 제외)하듯이 C 타입의 객체를 함수의 나머지 인수들 std:: forward < Args > ( args ) ... 로부터 생성한 후, 다음과 같은 동등한 호출을 수행합니다:

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 ) ) ;

(C++26 이후)

만약 R sized_range (C++26 이전) approximately_sized_range (C++26 이후) 를 만족하고 C reservable-container 를 만족하면, C 타입의 생성된 객체 c 는 초기 저장소 크기 ranges:: size ( r ) (C++26 이전) ranges :: reserve_hint ( r ) (C++26 이후) 로 저장소를 예약하여 새로운 요소 삽입 시 추가 할당을 방지할 수 있습니다. r 의 각 요소는 c 에 추가됩니다.

다음 두 조건이 모두 true 일 때 위 연산들은 유효합니다:

b) 그렇지 않은 경우, 반환 표현식은 다음과 동일합니다:

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 인 경우 범위 내에서 중첩된 범위 생성을 허용합니다.

그렇지 않으면 프로그램의 형식이 올바르지 않습니다.
2) Constructs an object of deduced type from the elements of 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 ; // 정의되지 않음
pointer operator - > ( ) const ; // 정의되지 않음
/*input-iterator*/ & operator ++ ( ) ; // 정의되지 않음
/*input-iterator*/ operator ++ ( int ) ; // 정의되지 않음
bool operator == ( const /*input-iterator*/ & ) const ; // 정의되지 않음

} ;
( 설명 전용* )

다음으로 정의된 /*DEDUCE-EXPR*/ 을 고려하십시오:

The call is equivalent to to < decltype ( /*DEDUCE-EXPR*/ ) >
( std:: forward < R > ( r ) , std:: forward < Args > ( args ) ... )
.
3,4) 완벽한 전달 호출 래퍼를 반환하며, 이는 또한 RangeAdaptorClosureObject 입니다.
5) true 인 경우, ranges:: sized_range 를 만족하며 예약 가능(reservable)한 자격이 있는 경우입니다.
6) Reference 타입의 요소 하나가 멤버 함수 호출 emplace_back , push_back , emplace 또는 insert 를 통해 Container 에 추가될 수 있으면 true 입니다.
7) 컨테이너에 하나의 요소를 추가하는 호출이 표현식-동등한 함수 객체를 반환합니다. 반환 표현식은 다음과 동등합니다:

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>
#ifndef __cpp_lib_format_ranges
#include <format>
#include <sstream>
auto print_aid(const auto& v)
{
    std::ostringstream out;
    out << '[';
    for (int n{}; const auto& e : v)
        out << (n++ ? ", " : "") << e;
    out << ']';
    return out;
}
template<typename T>
struct std::formatter<std::vector<T>, char>
{
    template<class ParseContext>
    constexpr ParseContext::iterator parse(ParseContext& ctx)
    {
        return ctx.begin();
    }
    template<class FmtContext>
    FmtContext::iterator format(auto const& s, FmtContext& ctx) const
    {
        auto out{print_aid(s)};
        return std::ranges::copy(std::move(out).str(), ctx.out()).out;
    }
};
template<typename T>
struct std::formatter<std::list<T>, char>
{
    template<class ParseContext>
    constexpr ParseContext::iterator parse(ParseContext& ctx)
    {
        return ctx.begin();
    }
    template<class FmtContext>
    FmtContext::iterator format(auto const& s, FmtContext& ctx) const
    {
        auto out{print_aid(s)};
        return std::ranges::copy(std::move(out).str(), ctx.out()).out;
    }
};
#endif
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("{}", vec);
    auto list = vec | std::views::take(3) | std::ranges::to<std::list<double>>();
    std::println("{}", list);
}
void ctor_demos()
{
    // 1.a.1) 직접 초기화
    {
        char array[]{'a', 'b', '\0', 'c'};
        // 인수 유형이 결과 값 유형으로 변환 가능한 경우:
        auto str_to = std::ranges::to<std::string>(array);
        // Equivalent to
        std::string str(array);
        // 결과 타입은 입력 범위가 아닙니다:
        auto re_to = std::ranges::to<std::regex>(array);
        // Equivalent to
        std::regex re(array);
    }
    // 1.a.2) from_range 생성자
    {
        auto list = {'a', 'b', '\0', 'c'};
        // 인수 타입이 결과 값 타입으로 변환 가능한 경우:
        auto str_to = std::ranges::to<std::string>(list);
        // Equivalent to
        // std::string str(std::from_range, list);
        // 결과 타입은 입력 범위가 아닙니다:
        [[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'};
        // 인수 타입이 결과 값 타입으로 변환 가능한 경우:
        auto devector_to = std::ranges::to<boost::컨테이너::devector<char>>(list);
        // Equivalent to
        boost::컨테이너::devector<char> devector(std::ranges::begin(list),
                                                  std::ranges::end(list));
        // 결과 타입은 입력 범위가 아닙니다:
        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);
    }
}

출력:

[2, 4, 6, 8]
[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]