에서 놀고 auto
있었습니다 std::pair
. 아래 코드에서 함수 f
는 std::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가 작동해야합니다. 아니면 안 돼요?
답변
문법 :
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이기 때문에 이것은 매우 혼란 스럽습니다 . 그러나 그것이 바로 그 방법입니다.