IT TIP

std :: transform () 및 toupper (), 일치하는 함수 없음

itqueen 2020. 12. 29. 08:10
반응형

std :: transform () 및 toupper (), 일치하는 함수 없음


이 질문에서 코드를 시도했습니다 C ++ std :: transform () 및 toupper () .. 왜 이것이 실패합니까?

#include <iostream>
#include <algorithm>

int main() {
  std::string s="hello";
  std::string out;
  std::transform(s.begin(), s.end(), std::back_inserter(out), std::toupper);
  std::cout << "hello in upper case: " << out << std::endl;
}

이론적으로는 Josuttis의 책에있는 예제 중 하나이므로 작동 했어야하지만 http://ideone.com/aYnfv 컴파일하지는 않습니다 .

GCC가 불만을 제기 한 이유 :

no matching function for call to ‘transform(
    __gnu_cxx::__normal_iterator<char*, std::basic_string
        <char, std::char_traits<char>, std::allocator<char> > >, 
    __gnu_cxx::__normal_iterator<char*, std::basic_string
        <char, std::char_traits<char>, std::allocator<char> > >, 
    std::back_insert_iterator<std::basic_string
        <char, std::char_traits<char>, std::allocator<char> > >,
    <unresolved overloaded function type>)’

여기에 뭔가 빠졌나요? GCC 관련 문제입니까?


::toupper대신 사용하십시오 std::toupper. 즉, toupper네임 스페이스에 정의 된 것이 아니라 전역 네임 스페이스에 정의됩니다 std.

std::transform(s.begin(), s.end(), std::back_inserter(out), ::toupper);

작동 : http://ideone.com/XURh7

코드가 작동하지 않는 이유 : toupper이름 std을 확인할 때 문제를 일으키는 네임 스페이스에 또 다른 오버로드 된 함수 가 있습니다. 컴파일러는 단순히 std::toupper. 이것이 컴파일러가 unresolved overloaded function type오류 메시지에서 오버로드가 있음을 나타내는 이유 입니다.

따라서 컴파일러가 올바른 오버로드를 해결하는 데 도움이되도록 다음 std::toupper과 같이 캐스팅 해야합니다.

(int (*)(int))std::toupper

즉, 다음이 작동합니다.

//see the last argument, how it is casted to appropriate type
std::transform(s.begin(), s.end(), std::back_inserter(out),(int (*)(int))std::toupper);

직접 확인해보세요 : http://ideone.com/8A6iV


문제

std::transform(
    s.begin(),
    s.end(),
    std::back_inserter(out),
    std::toupper
);

' transform(__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::back_insert_iterator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, <unresolved overloaded function type>)'에 대한 호출과 일치하는 함수가 없습니다.

이것은 잘못된 오류입니다. 흥미로운 부분은 호출에 대해 "일치하는 함수가 없음"이 아니라 일치하는 함수가없는 이유 입니다.

이유 는 " <unresolved overloaded function type>" 의 함수 참조를 인수로 전달하고 GCC는이 오버로드 해결 실패보다는 호출에서 오류를 선호하기 때문입니다.


설명

먼저 C ++에서 C 라이브러리가 상속되는 방식을 고려해야합니다. <ctype.h>기능이 int toupper(int)있습니다.

C ++는 다음을 상속합니다.

[n3290: 21.7/1]:표 74, 75, 76, 77, 78, 79가 설명하는 헤더를 <cctype>, <cwctype>, <cstring>, <cwchar>, <cstdlib>(문자 변환)하고 <cuchar>, 각각.

[n3290: 21.7/2]:이 헤더의 내용은 C 표준 라이브러리 헤더와 동일하게한다 <ctype.h>, <wctype.h>, <string.h>, <wchar.h>, 및 <stdlib.h>상기 C 유니 TR 헤더 <uchar.h>각각 [...]

[n3290: 17.6.1.2/6]:C에서 함수로 정의 된 이름은 C ++ 표준 라이브러리에서 함수로 정의되어야합니다.

그러나 using <ctype.h>은 더 이상 사용되지 않습니다.

[n3290: C.3.1/1]: 표준 C 라이브러리와의 호환성을 위해 C ++ 표준 라이브러리는 18 개의 C 헤더 (D.5)를 제공하지만 C ++에서는 더 이상 사용되지 않습니다.

C에 액세스하는 방법 toupper은 C ++ 이전 버전과의 호환성 헤더를 사용하는 것 <cctype>입니다. 이러한 헤더의 경우 콘텐츠가 네임 스페이스 로 이동되거나 복사됩니다 (구현에 따라 다름) std.

[n3290: 17.6.1.2/4]:[..] 그러나 C ++ 표준 라이브러리에서 선언 (C에서 매크로로 정의 된 이름 제외)은 네임 스페이스 std의 네임 스페이스 범위 (3.3.6) 내에 있습니다. 이러한 이름이 전역 네임 스페이스 범위 내에서 처음 선언 된 다음 명시 적 using-declarations (7.3.3)에 의해 네임 스페이스 std에 삽입되는지 여부는 지정되지 않습니다 .

그러나 C ++ 라이브러리는 헤더에 새로운 로케일 고유의 기능 템플릿 소개 <locale>것, 또한 전화 toupper(네임 스페이스에, 물론을 std) :

[n3290: 22.2]:[..] template <class charT> charT toupper(charT c, const locale& loc);[..]

따라서를 사용할 때 선택할 수 std::toupper있는 두 가지 과부하가 있습니다. 어떤 기능을 사용하고 싶은지 GCC에 알려주지 않았기 때문에 과부하를 해결할 std::transform수없고 호출을 완료 할 수 없습니다.


Disparity

Now, the OP of that original question did not run into this problem. He likely did not have the locale version of std::toupper in scope, but then again you didn't #include <locale> either!

However:

[n3290: 17.6.5.2]: A C++ header may include other C++ headers.

So it just so happens that either your <iostream> or your <algorithm>, or headers that those headers include, or headers that those headers include (etc), lead to the inclusion of <locale> on your implementation.


Solution

There are two workarounds to this.

  1. You may provide a conversion clause to coerce the function pointer into referring to the overload that you wish to use:

    std::transform(
       s.begin(),
       s.end(),
       std::back_inserter(out),
       (int (*)(int))std::toupper  // specific overload requested
    );
    
  2. You may remove the locale version from the overload set by explicitly using the global toupper:

    std::transform(
       s.begin(),
       s.end(),
       std::back_inserter(out),
       ::toupper                  // global scope
    );
    

    However, recall that whether or not this function in <cctype> is available is unspecified ([17.6.1.2/4]), and using <ctype.h> is deprecated ([C.3.1/1]).

    Thus, this is not the option that I would recommend.


(Note: I despise writing angle brackets as if they were part of header names — they are part of #include syntax, not header names — but I've done it here for consistency with the FDIS quotes; and, to be honest, it is clearer...)

ReferenceURL : https://stackoverflow.com/questions/7131858/stdtransform-and-toupper-no-matching-function

반응형