gpt4 book ai didi

c++ - STL Character Traits 的重点是什么?

转载 作者:IT老高 更新时间:2023-10-28 12:05:43 26 4
gpt4 key购买 nike

我注意到在我的 SGI STL 引用拷贝中,有一个关于 Character Traits 的页面,但我看不到它们是如何使用的?它们会替换 string.h 函数吗? std::string 似乎没有使用它们,例如length()方法在 std::string不使用字符特性 length()方法。为什么会存在 Character Traits 并且它们是否曾在实践中使用过?

最佳答案

字符特征是流和字符串库的一个极其重要的组成部分,因为它们允许流/字符串类将存储哪些字符的逻辑与应该对这些字符执行的操作的逻辑分开。

首先,默认的字符特征类,char_traits<T> , 在 C++ 标准中被广泛使用。例如,没有名为 std::string 的类。 .相反,有一个类模板 std::basic_string看起来像这样:

template <typename charT, typename traits = char_traits<charT> >
class basic_string;

然后, std::string被定义为
typedef basic_string<char> string;

类似地,标准流定义为
template <typename charT, typename traits = char_traits<charT> >
class basic_istream;

typedef basic_istream<char> istream;

那么为什么这些类的结构是这样的呢?为什么我们应该使用一个奇怪的特征类作为模板参数?

原因是在某些情况下我们可能想要一个字符串,就像 std::string ,但具有一些略有不同的属性。一个典型的例子是,如果您想以一种忽略大小写的方式存储字符串。例如,我可能想创建一个名为 CaseInsensitiveString 的字符串。这样我就可以拥有
CaseInsensitiveString c1 = "HI!", c2 = "hi!";
if (c1 == c2) { // Always true
cout << "Strings are equal." << endl;
}

也就是说,我可以有一个字符串,其中两个仅区分大小写的字符串比较相等。

现在,假设标准库作者在不使用特征的情况下设计了字符串。这意味着我在标准库中有一个非常强大的字符串类,但在我的情况下完全没有用。我不能重用这个字符串类的大部分代码,因为比较总是与我希望它们的工作方式相反。但是通过使用traits,实际上可以重用驱动 std::string的代码。获取不区分大小写的字符串。

如果您打开 C++ ISO 标准的拷贝并查看字符串比较运算符如何工作的定义,您会发现它们都是根据 compare 定义的。功能。这个函数又通过调用来定义
traits::compare(this->data(), str.data(), rlen)

哪里 str是您要比较的字符串和 rlen是两个字符串长度中较小的一个。这其实挺有意思的,因为这意味着 compare的定义直接使用 compare由指定为模板参数的特征类型导出的函数!因此,如果我们定义一个新的traits 类,那么定义 compare为了不区分大小写地比较字符,我们可以构建一个行为类似于 std::string 的字符串类。 ,但不区分大小写!

这是一个例子。我们继承自 std::char_traits<char>获取我们未编写的所有函数的默认行为:
class CaseInsensitiveTraits: public std::char_traits<char> {
public:
static bool lt (char one, char two) {
return std::tolower(one) < std::tolower(two);
}

static bool eq (char one, char two) {
return std::tolower(one) == std::tolower(two);
}

static int compare (const char* one, const char* two, size_t length) {
for (size_t i = 0; i < length; ++i) {
if (lt(one[i], two[i])) return -1;
if (lt(two[i], one[i])) return +1;
}
return 0;
}
};

(请注意,我还在此处定义了 eqlt,它们分别比较了相等和小于的字符,然后根据此函数定义了 compare)。

现在我们有了这个 traits 类,我们可以定义 CaseInsensitiveString微不足道的
typedef std::basic_string<char, CaseInsensitiveTraits> CaseInsensitiveString;

瞧!我们现在有一个字符串,它不区分大小写地处理所有内容!

当然,使用traits除了这个还有其他原因。例如,如果你想定义一个使用一些固定大小的底层字符类型的字符串,那么你可以专门化 char_traits在该类型上,然后从该类型制作字符串。例如,在 Windows API 中,有一个类型 TCHAR这是一个窄字符或宽字符,具体取决于您在预处理期间设置的宏。然后你可以用 TCHAR 制作字符串s 通过写作
typedef basic_string<TCHAR> tstring;

现在你有一个字符串 TCHAR s。

在所有这些示例中,请注意我们刚刚定义了一些特征类(或使用了一个已经存在的类)作为某个模板类型的参数,以便获取该类型的字符串。重点在于 basic_string作者只需要指定如何使用特征,我们就可以神奇地让它们使用我们的特征而不是默认特征来获取具有一些细微差别或怪癖的字符串,而不是默认字符串类型的一部分。

希望这有帮助!

编辑 :正如@phoji 所指出的,这种特征的概念不仅被 STL 使用,也不是特定于 C++ 的。作为完全无耻的自我宣传,前段时间我写了 an implementation of a ternary search tree (一种基数树 described here )使用特征来存储任何类型的字符串,并使用客户端希望它们存储的任何比较类型。如果您想查看在实践中使用它的示例,这可能是一个有趣的阅读。

编辑 : 回应您的声明 std::string不使用 traits::length ,事实证明它在几个地方确实如此。最值得注意的是,当您构建 std::string 时出 char* C 风格的字符串,字符串的新长度是通过调用 traits::length 导出的在那根弦上。看来 traits::length主要用于处理 C 风格的字符序列,这是 C++ 中字符串的“最小公分母”,而 std::string用于处理任意内容的字符串。

关于c++ - STL Character Traits 的重点是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5319770/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com