【问题标题】:How to use std::toupper in std::for_each?如何在 std::for_each 中使用 std::toupper?
【发布时间】:2015-05-15 03:20:04
【问题描述】:

我正在尝试使用 std::toupper 函数将字符串的小写字符转换为对应的大写字符,并且我正在使用 std::for_each 算法迭代字符串中的字符。

#include <iostream>
#include <string>
#include <algorithm>
#include <locale>

std::string convert_toupper(std::string *x) {
  return std::toupper(*x, std::locale());
}

int main() {
  std::string x ("example");

  std::for_each(x.begin(), x.end(), convert_toupper);
}

当我编译这段代码时,我收到了这个错误:

In file included from /usr/include/c++/4.8/algorithm:62:0,
                 from me2.cpp:3:
/usr/include/c++/4.8/bits/stl_algo.h: In instantiation of ‘_Funct std::for_each(_IIter, _IIter, _Funct) [with _IIter = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >; _Funct = std::basic_string<char> (*)(std::basic_string<char>*)]’:
me2.cpp:13:52:   required from here
/usr/include/c++/4.8/bits/stl_algo.h:4417:14: error: invalid conversion from ‘char’ to ‘std::basic_string<char>*’ [-fpermissive]
  __f(*__first);
              ^

使用 std::toupper 和 std::for_each 将字符从小写转换为大写的正确方法是什么?

【问题讨论】:

    标签: c++ c++11 stl


    【解决方案1】:

    string 基本上是chars 的容器。当您迭代 string 时,您将一次只使用一个 char。所以你传入for_each的函子将被char调用,而不是string*,因此错误:

    invalid conversion from ‘char’ to ‘std::basic_string<char>*
    

    正确的实现应该是:

    std::for_each(x.begin(), x.end(), std::toupper);
    

    然而,这将无济于事。 toupper 的返回值将被忽略,并且该函数没有副作用。如果您真的想将字符串转换为大写版本,则必须使用std::transform:

    std::transform(x.begin(), x.end(), x.begin(), std::toupper);
    

    或者,提供语言环境:

    char locale_upper(char c) { return std::toupper(c, std::locale()); }
    std::transform(x.begin(), x.end(), x.begin(), locale_upper);
    

    或者,在 C++11 中:

    std::transform(x.begin(), x.end(), x.begin(), [](char c){
        return std::toupper(c, std::locale());
    });
    

    此时您不妨只使用for-loop:

    for (char& c : x) {
        c = std::toupper(c, std::locale());
    }
    

    【讨论】:

    • 如果不进行本地化,我会将std::toupper 替换为::toupper(来自&lt;ctype.h&gt;)。否则,包括&lt;locale&gt; 将在调用std::transform 时产生歧义,因为后者无法推断出std::toupper 的正确类型(现在将有2 个函数,一个在&lt;cctype&gt; 中,一个在&lt;locale&gt; ,具有不同的签名,因此您必须手动指定函子类型的签名)。
    • @vsoftco:并非不可能,我认为您可以为此使用演员表。
    • 我认为将 std::for_each 与 lambda [](char&amp; c){ c = std::toupper(c);} 一起使用是合法的。虽然range-based for 的其他解决方案更优雅。
    • @JesseGood 一个 lambda 是可以的,一个强制转换不是(你必须指定类型,否则模板化的 std::transform 不知道选择哪个重载;并且指定类型很痛苦,因为函子是类型参数列表中的最后一个)。
    • 您不应将char 传递给std::toupper(或::toupper)的单参数版本。
    【解决方案2】:

    &lt;locale&gt; 中,您已经拥有将小写字符串转换为大写的std::ctype::toupper 函数。函数调用有点棘手,但非常紧凑:

    std::use_facet<std::ctype<char>>(std::locale()).toupper(&x[0], &x[0] + x.size());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-09
      • 2014-04-01
      • 2011-06-12
      相关资源
      最近更新 更多