Какой из них в С++?

Учитывая string foo, я написал ответы о том, как использовать cctype tolower для преобразования символов в нижний регистр

transform(cbegin(foo), cend(foo), begin(foo), static_cast<int (*)(int)>(tolower))

Но я начал рассматривать locale tolower, который можно использовать следующим образом:

use_facet<ctype<char>>(cout.getloc()).tolower(data(foo), next(data(foo), foo.size()));
  • Есть ли причина предпочесть один из них над другим?
  • Отличается ли их функциональность вообще?
  • Я имею в виду, кроме того, что tolower принимает и возвращает int, который, я полагаю, является лишь некоторым устаревшим материалом C?

Ответ 1

Следует отметить, что разработчики языка знали cctype tolower, когда был создан locale tolower. Он улучшен двумя основными способами:

  • Как упоминается в progressive_overload answer, версия locale допускает использование facet ctype, даже измененного пользователем, без необходимости перетасовки новый LC_CTYPE через setlocale и восстановление предыдущего LC_CTYPE
  • Из раздела 7.1.6.2 [dcl.type.simple] 3:

Определяется реализацией, представлены ли объекты типа char в виде подписанных или неподписанных величин. Спецификатор signed заставляет char объекты подписываться

Что создает потенциал для undefined поведения с cctype версией tolower, если он аргумент:

Не представляется в качестве unsigned char и не равно EOF

Таким образом, существует дополнительный вход и выход static_cast, требуемый версией cctype tolower, предоставляющей:

transform(cbegin(foo), cend(foo), begin(foo), [](const unsigned char i){ return tolower(i); });

Так как версия locale работает непосредственно на char, нет необходимости в преобразовании типа.

Итак, если вам не нужно выполнять преобразование в другом facet ctype, он просто становится вопросом стиля, предпочитаете ли вы transform лямбда, требуемую версией cctype, или вы предпочитаете версию locale:

use_facet<ctype<char>>(cout.getloc()).tolower(data(foo), next(data(foo), size(foo)));

Ответ 2

К сожалению, оба одинаково плохи. Хотя std::string претендует на то, что это строка, закодированная в utf-8, но не методы/функции (в том числе tolower), действительно знают utf-8. Таким образом, tolower/tolower + locale может работать с символами, которые являются одиночными байтами (= ASCII), они будут терпеть неудачу для каждого другого набора языков.

В Linux я бы использовал библиотеку ICU. В Windows я бы использовал функцию CharUpper.

Ответ 3

В первом случае (cctype) языковой стандарт задается неявно:

Преобразует заданный символ в нижний регистр в соответствии с символом правила преобразования, определенные в текущем установленном языковом языке C.

http://en.cppreference.com/w/cpp/string/byte/tolower

Во втором (локальном) случае вам нужно явно установить локаль:

Преобразует параметр c в его нижний регистр, если c является прописным буквы и имеет эквивалент в нижнем регистре, как определено ctype грань locale loc. Если такое преобразование невозможно, значение возвращается с неизменным.

http://www.cplusplus.com/reference/locale/tolower/