std :: pair <auto, auto> 반환 유형


16

에서 놀고 auto있었습니다 std::pair. 아래 코드에서 함수 fstd::pair템플릿 매개 변수에 따라 유형 중 하나를 반환해야합니다 .

실제 예 :

실시 예 1

template <unsigned S>
auto f()
{
    if constexpr (S == 1)
        return std::pair{1, 2}; // pair of ints
    else if constexpr (S == 2)
        return std::pair{1.0, 2.0}; // pair of doubles
    else
        return std::pair{0.0f, 0.0f}; // pair of floats
}

이것은 gcc 9.2, gcc 10.0, clang 9.0 및 clang 10.0에서 작동합니다.

다음으로, std::pair명확한 이유로 반환 유형을 명시 적으로 작성하고 싶었습니다 .

실시 예 2

template <unsigned S>
std::pair<auto, auto> f()
{
    if constexpr (S == 1)
        return {1, 2};
    /* ... */
}

gcc 9.2 / 10.0과 clang 9.0 / 10.0 모두 컴파일에 실패했습니다.

gcc 9.2

error: invalid use of 'auto'
error: template argument 1 is invalid // first argument (auto) of std::pair
error: template argument 2 is invalid // second argument (auto) of std::pair
error: cannot convert '<brace-enclosed initializer list>' to 'int' in return

마지막 오류 메시지에서 GCC 9.2은 믿는 것 같다 std::pair<auto, auto>입니다 int. 이것을 어떻게 설명 할 수 있습니까?

gcc 10.0

error: returning initializer list

이 오류는 이해할 만하지 만 생성자 std::pair가 호출 될 것으로 기대 했거나 여기에 누락 된 것이 있습니까?

클랑 9.0 및 10.0

'auto' not allowed in template argument
excess elements in scalar initializer
no matching function for call to 'f'

좋아, clang은 이것을 좋아하지 않습니다. 두 번째 오류 메시지에서 clang은 반환 유형이이라고 생각합니다 int.

마지막으로 gcc 10.0으로 컴파일하여 얻은 오류를 수정하기 위해 std::pair명시 적으로 반환하기로 결정했습니다 .

실시 예 3

template <unsigned S>
std::pair<auto, auto> f()
{
    if constexpr (S == 1)
        return std::pair{1, 2};
    /* ... */
}

클랑 9.0 및 10.0

이전과 동일하지만 추가로

no viable conversion from returned value of type 'std::pair<int, int>' to function return type 'int'

여기 clang은 여전히 ​​우리가 int?

gcc 9.2

이전과 동일합니다.

gcc 10.0

효과가있다!

일부 기능은 여전히 ​​구현해야하거나 위에서 설명한 상황 중 하나에서 옳고 다른 컴파일러가 있습니까? 제 생각에는 예제 2가 작동해야합니다. 아니면 안 돼요?

답변:


23

문법 :

std::pair<auto, auto> f() { return std::pair(1, 2); }
~~~~~~~~~~~~~~~~~~~~~

원래 Concepts TS의 일부 였지만 C ++ 20의 일부인 Concepts 제안에는 포함되지 않았습니다. 따라서 C ++ 20의 유일한 자리 표시 자 유형은 auto(및 이와 유사한 변형 auto**) decltype(auto)및 제한된 자리 표시 자 Concept auto및 변형입니다. 이러한 종류의 중첩 자리 표시 자 유형은 매우 유용하지만 C ++ 20의 일부가 아니므로 함수 선언이 잘못 구성됩니다.

gcc는 개념 TS를 구현했기 때문에 gcc가 허용하며이 기능을 유지하기로 결정한 것 같습니다. clang은 TS를 구현하지 않았으므로 TS를 구현하지 않았습니다.

어느 쪽이든, 이것은 :

std::pair<auto, auto> f() { return {1, 2}; }

항상 잘못된 것입니다. 구문의 의미는 반환 유형을 추론 한 다음 pair<T, U>일부 유형 T과 일치하도록 요구한다는 것 U입니다. 우리는 기본적으로 발명 된 기능을 호출하려고합니다.

template <typename T, typename U>
void __f(std::pair<T, U>);

__f({1, 2}); // this must succeed

그러나 {1, 2}braced-init-list에는 유형이 없습니다. 아마도 이것은 (이와 같은 간단한 경우에는 이해하기 쉽기 때문에) 탐구해야 할 것이지만 결코 허용되지 않았습니다. 따라서 그것을 거부하는 것은 어느 쪽이든 맞습니다.

마지막으로 :

gcc 9.2 std::pair<auto, auto>int. 이것을 어떻게 설명 할 수 있습니까?

어떤 이유로 (아마도 암시적인 C 레거시로 인해 int) gcc가 유형을 인식하거나 이해하지 못하면 int오류 메시지에서 자리 표시 자로 만 사용 됩니다. 명백히 int소스 코드가 아닌 gcc이기 때문에 이것은 매우 혼란 스럽습니다 . 그러나 그것이 바로 그 방법입니다.


"braced-init-list에 형식 인수가 없습니다"라는 것이 명확하지 않습니다. std :: pair <int, int> f () {return {1,2}; }가 작동하고 {1,2}에는 유형이 없습니다 (내가 이해 한대로 std :: pair <int, int>의 생성자를 호출합니다). 아마도 <auto, auto>를 사용하면 컴파일러는 초기화 목록 {1, 2}에서 1과 2의 유형을 추론 할 수 없습니까?
mfnx

@mfnx 타입 인수 는없고 타입도 없습니다. 괄호 init 목록은 알려진 유형의 초기화와 같은 특정 상황에서만 사용할 수 있습니다. 그러나 유형이 없기 때문에 공제에 사용할 수 없습니다. 를 제외하고 auto x = {1, 2};작동하지만 모든 유형이 동일한 경우에만 가능합니다.
Barry

2
대부분의 컴파일러는 첫 번째 오류에서 중지하는 대신 오류를 복구하여 추가 오류를보고 할 수 있습니다. 이것은 일반적으로 모든 것이 파싱 할 가정 것은 의미합니다 int. 그것은 int오류 메시지의 자리 표시자가 아닙니다 . 컴파일러는 실제로 그것이이라고 생각합니다 int. (이를 명확하게하기 위해 gcc는 아마 "inting int"라고 말했을 것입니다.)
Raymond Chen

2
확장을위한 또 다른 가능한 길은 std::pair __f{1,2};작동하기 때문에 반환 유형에 대한 클래스 템플릿 인수 공제를 허용하는 것 입니다.
Davis Herring

2
@DavisHerring 나는 정말로 std::optional f() { return 4; }일하고 싶지 않습니다 .
Barry
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.