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


теоретически это должно было сработать, поскольку это один из примеров в книге Джосуттиса, но он не компилируется 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?

771   2  

2 ответов:

просто использовать ::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>)'

это вводящая в заблуждение ошибка; интересная часть заключается не в том, что для вызова" нет соответствующей функции", а почему там нет соответствующей функции.

The почему это то, что вы передаете ссылку на функцию "<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 Unicode TR заголовок <uchar.h>, соответственно [..]

[n3290: 17.6.1.2/6]:имена, которые определены как функции в C должны быть определены как функции в стандартной библиотеке C++.

, но через <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) в пространство имен (3.3.6) из пространство имен std. это не определено будут ли эти имена сначала объявлены в глобальном пространстве имен область и затем вводятся в пространство имен std с помощью явного используя объявления (7.3.3).

но библиотека C++ также вводит новый, специфичный для языкового стандарта шаблон функции в заголовке <locale>, это и под названием toupper (конечно, в пространстве имен std):

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

поэтому, когда вы используете std::toupper, есть два перегрузки на выбор. Поскольку вы не сказали GCC, какую функцию вы хотите использовать, перегрузка не может быть решена, и ваш вызов std::transform не может быть завершено.


разрыв

теперь ОП этого первоначального вопроса не столкнулся с этой проблемой. У него, вероятно, не было языковой версии std::toupper в области видимости, но опять же вы не #include <locale> либо!

:

[n3290: 17.6.5.2]: заголовок C++ может включать в себя другие заголовки c++.

так так получилось что либо <iostream> или <algorithm>, или заголовки, которые эти заголовки включают, или заголовки, которые те заголовки включают (etc), приводят к включению <locale> на реализацию.


решение

есть два обходных пути этот.

  1. вы можете предоставить предложение преобразования, чтобы принудить указатель функции ссылаться на перегрузку, которую вы хотите использовать:

    std::transform(
       s.begin(),
       s.end(),
       std::back_inserter(out),
       (int (*)(int))std::toupper  // specific overload requested
    );
    
  2. вы можете удалить версию локали из набора перегрузки, явно используя глобальный toupper:

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

    однако, напомним, что ли эта функция в <cctype> доступно не указано ([17.6.1.2/4]), и с помощью <ctype.h> устарел ([C.3.1/1]).

    таким образом, это не тот вариант, который я бы порекомендовал.


(Примечание: я презираю написание угловых скобок, как если бы они были частью имен заголовков - они являются частью #include синтаксис, а не имена заголовков - но я сделал это здесь для согласованности с цитатами FDIS; и, честно говоря, это и понятнее...)

Comments

    Ничего не найдено.