Какова цель std::char_traits::assign()?

void assign(char_type& to, char_type from);

Почему вы не можете просто использовать оператор присваивания вместо этой функции? Для чего это используется?

2 ответа

Вы фактически используете эту функцию каждый раз, когда используете std:: string:). std:: string на самом деле является typedef для std:: basic_string, который определяется как:

template< 
    class CharT, 
    class Traits = std::char_traits<CharT>, 
    class Allocator = std::allocator<CharT>
> class basic_string;

(см. это). Обратите особое внимание на параметр шаблона Черты. Если вы были так склонны, параметр шаблона Traits позволяет вам настраивать определенные атрибуты поведения строкового класса. Одним из этих свойств является то, что происходит, когда вы делаете назначение.

Вот пример использования этого. Это заставит назначения быть строчными.

#include <string>
#include <iostream>
#include <cctype>

struct ci_char_traits : public std::char_traits<char> {
    static void assign(char& r, const char& a)
    {
        r = std::tolower(a);
    }

    static char* assign(char* p, std::size_t count, char a)
    {
        for (std::size_t i = 0; i < count; ++i)
        {
            p[i] = std::tolower(a);
        }
    }
};

typedef std::basic_string<char, ci_char_traits> ci_string;

std::ostream& operator<<(std::ostream& os, const ci_string& str) {
    return os.write(str.data(), str.size());
}

int main()
{
    ci_string s1 = "Hello";

    // This will become a lower-case 'o'
    s1.push_back('O');

    // Will replace 'He' with lower-case 'a'
    s1.replace(s1.begin(), s1.begin()+2, 1, 'A');

    std::cout << s1 << std::endl;
}

Это связано с тем, что черты характера являются способом создания вариантов стандартных классов (например, строк), и оператор примитивного типа может на самом деле не быть тем, что вам нужно.

Например, рассмотрим класс, который хранит строки без учета регистра; вы могли бы реализовать assign() таким образом, что хранит одно и то же и для заглавной буквы, и для строчной версии. (В этом отношении другие операции черты характера, такие как равенство, также должны быть переопределены.)

Вы можете написать свой собственный класс персонажей и определить его operator=. Но вам может быть удобно использовать основные типы символов, такие какchar, wchar_t, char16_t, char32_t или char8_t. Такие неклассовые типы не позволяют вам перегружать их операторы, и поэтомуchar_traits предоставляет способ настройки небольшого набора их общих операций (как предлагается в других ответах, это может позволить, например, символьные операции без учета регистра).

template < 
  class CharT, 
  class Traits = std::char_traits<CharT>, 
  class Allocator = std::allocator<CharT>
> class basic_string;

std::basic_stringхороший пример; второй параметр шаблона,Traits, позволяет получить доступ к такой настройке. Также рассмотрим третий параметр шаблона,Allocator, что позволяет пользователю std::basic_stringчтобы настроить внутреннее распределение памяти. Это может привести к аналогичному вопросу: почему бы просто не использоватьoperator new?

Менее важно, но обратите внимание, что C++20 представил вторую перегрузку std::char_traits<CharT>::assign:

static constexpr char_type* assign(char_type* p, std::size_t count, char_type a);
Другие вопросы по тегам