【问题标题】:When do you require to use decltype in C++什么时候需要在 C++ 中使用 decltype
【发布时间】:2017-08-17 19:50:09
【问题描述】:

我正在学习 C++,并在 C++ 入门中找到了以下代码:

int main() {

string s("some string");
for(decltype(s.size()) index = 0; index != s.size() && !isspace(s[index]); ++index)
    s[index] = toupper(s[index]);

cout << s;

}

我理解代码将字符串中的第一个单词大写,输出为

SOME string

我很好奇的是为什么你需要使用decltype(s.size()) 来声明索引的类型。如果我将其更改为int index =0,代码仍然可以正常编译和运行。对我来说使用int 似乎更容易。我想我在这里遗漏了一些导入概念,任何反馈都会非常有帮助。谢谢!

【问题讨论】:

  • 我认为关键是 string::size() 的返回值不太可能是 int,使用 decltype 可以为您提供正确的类型..
  • 有这样一个typedef,称为std::string::size_type
  • 看起来像是一个人为的例子,因为在实践中,人们会简单地使用 std::size_t 作为索引类型,或者通过使用 range-for 循环 for(auto&amp; c: s){ if(isspace(c)) break; c = toupper(c); } 来摆脱索引变量。

标签: c++


【解决方案1】:

您不需要使用decltype(s.size()) 来声明类型,但将其声明为int 不一定是个好主意。或者至少这不是一个好习惯。

decltype(s.size()) 的字面意思是“这种类型应该与std::string 用于存储字符串长度的任何类型相同”。在大多数 C++ 实现中,这是size_t,它可以是无符号的 64 位整数(在大多数情况下)或无符号的 32 位整数。在任何一种情况下,int(已签名并且可能不会是 64 位)都不会代表 std::string 对象的整个可能大小范围,在特殊情况下,它可能大于 2.1亿个字符。在这些情况下,如果您将类型定义为 int,您将面临未定义行为的风险。

请注意,在我的代码中,我通常只写for(size_t index = 0; index &lt; string.size(); index++),因为这样更简单。但如果你想保证代码在所有平台上都能正常运行,for(decltype(string.size()) index = 0; index &lt; string.size(); index++) 是最安全的代码版本。

【讨论】:

  • 这不是猜测的问题。 std::string::size_type 明确无误地指定。
【解决方案2】:

他们使用decltype(s.size()) 而不是int 的原因是因为使用int 可能会导致溢出,这是未定义的行为。 std::string::size() 返回一个无符号整数类型,可以存储您可以创建的最大大小的字符串。如果int 不能保存该值并且字符串是该大小,那么尝试将int 运行到该值将永远无法工作

在 C++11 之前,您必须使用 std::string::size_type,如果您更改了类型,则必须更改 std::string 部分。现在我们有了 C++11 及更高版本,我们不再需要这样做。编译器知道事物的类型,所以如果我们使用decltype(s.size()),我们就会得到正确的类型,如果我们改变了s,那么for循环中就没有什么需要改变的了。从可维护性的角度来看,这非常好。

【讨论】:

    【解决方案3】:

    好吧,decltype 更有用的一个地方是:

    template<class T1, class T2>
    auto mul(T1 a, T2 b) -> decltype(a*b){
      return a*b;
    }
    

    此模板将允许您将两个可能是不同类型的东西相乘,并返回将两者相乘的结果的正确类型。一个假设的例子可能是将两个矩阵相乘,从而产生一些中间类型类,将实际计算推迟到很久以后。

    【讨论】:

    • 非常感谢您的评论。如您所知,我正在学习 C++,所以我不完全理解这行 'auto mul(T1 a, T2 b) -> decltype(a*b)' 你能指点我参考以便更好地理解吗?
    • 查找称为“尾随返回类型”的内容。这解决了您不能谈论返回类型通常去的ab 的问题,因为这些标识符尚未声明。因此,您可以将返回类型声明为auto,其实质上是“在参数列表之后查找返回类型”。此时ab 已被声明,现在decltype 可以使用这些标识符来确定结果类型。这是 C++11 的事情。
    【解决方案4】:

    什么时候需要在 C++ 中使用 decltype

    我能想到以下几点。

    当您希望编译器从以下位置推断类型时:

    1. 另一个对象的类型。
    2. 函数的返回类型。

    你也可以使用:

    auto size = s.size();
    for(decltype(size) index = 0; index != size && !isspace(s[index]); ++index)
        s[index] = toupper(s[index]);
    

    【讨论】:

      【解决方案5】:

      原因是 字符串类成员函数s.size()的类型为string::size_type,它是无符号的,可以 持有任意长度的字符串。 在这段代码中,index 是一个变量,随着循环的运行而增加,它会增加 直到它的值等于s.size()-1。 字符串的长度可以是任意大小。所以我们不能将int 用于更长的字符串,因为它 只能保存特定范围的值。因此,如果字符串的大小较长 index 可以保存该值 任何大小,不显示任何错误。

      【讨论】:

        猜你喜欢
        • 2011-07-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-16
        • 2012-12-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多