remove_if(str.begin(), str.end(), ::isspace); ::isspace 是什么意思?

remove_if(str.begin(), str.end(), ::isspace); what does the ::isspace means?

我最近想找到一种使用 STL 来 trim 字符串的方法。我看到有人用

remove_if(str.begin(), str.end(), isspace);

我发现isspace是stl中的一个函数,header是<ctype.h>。我将上面的代码和头文件放在我的函数中,然后它无法通过编译。编译器抱怨 isspace.

我试试

remove_if(str.begin(), str.end(), std::isspace);

还是编译不通过

然后我发现另一个人用

remove_if(str.begin(), str.end(), ::isspace);

我试了一下,可以通过编译。

我的问题是

  1. 为什么我用前两种方式都编译不通过

  2. ::isspace 是什么意思?是要提它属于STL还是别的?我对 ::?

  3. 的用法感到困惑

std::isspace是C++中的一个重载函数,在<locale>中声明了一个模板函数。允许实现默默地包含额外的 headers 你没有要求,许多人这样做了。他们这样做是因为他们在内部使用了那些额外的 headers.

通常,传递给 std::isspace 的参数将决定选择哪个重载,但在您的情况下,您没有传递任何参数,您只是试图确定其地址。

::isspace 有效,因为那不是重载函数。

就像

template <typename T>
void f(T) { }

void g(int) { }
void h() { f(g); } // okay, g is not an overloaded function

void i(int) { }
void i(char) { }
void j() { f(i); } // error, the compiler cannot know whether you want the void(int)
                   // function, or the void(char) one

评论中告诉你的是正确的,确保它有效的简单方法是根本不传递 isspace 的地址,而是创建一个你自己的调用 isspace。出于其他原因你无论如何都需要这样做,但它也很好地完全避免了这个问题。

::isspace 表示您正在显式调用全局方法 isspace。 C 标准库方法都是全局方法,<ctype.h> 是 C 标准库头文件。

C 中不存在命名空间,因此在使用 C 库头文件时,不使用 std 命名空间。使用 std 命名空间的 <ctype.h> 的 C++ 对应项是 <cctype>.

前导 :: 表示法在您尝试处理名称冲突时很有用。例如,您可以使用这样的代码...

void DoSomething(void);

class Foo {
  void DoSomething (void); // Uhoh, this method shadows the global DoSomething.
  void DoSomethingElse(void) {
    Foo::DoSomething(); // Calls the class local DoSomething()
    ::DoSomething(); // Calls the global DoSomething()
  }
};

请注意,在 C++ 中有两个 std::ispace 函数的两个版本,即两个重载。其中第一个在 <cctype> C-compatibility header 中定义为

#include <ctype.h>
namespace std { using isspace = ::isspace; }

其中 <ctype.h> 是相应的 C header,它应该将 isspace(在全局命名空间中,即 ::isspace)定义为:

int isspace(int);

第二个重载在<locale>中定义为:

namespace std {
  template<class charT> bool isspace(charT, const locale &);
}

如果出于某种原因您(直接或间接)包含了 <cctype><locale>,您会得到两个 std::isspace 的覆盖,但一个全局 ::isspace 函数。因此,直接使用 ::isspace 会很好,但使用 std::isspace 会出错,因为编译器无法解决使用哪个重载的歧义。

要解决此问题,您可以通过将函数强制转换为所需类型来告诉编译器您指的是哪个重载,例如:

std::remove_if(str.begin(),
               str.end(),
               static_cast<int(&)(int)>(std::isspace)); // reference to function
    // Or even static_cast<int(*)(int)>(std::isspace)); // pointer to function

PS:文字 :: 称为范围解析运算符,因此在 A::b 的情况下,它指的是可达命名空间中称为 b 的东西 A 在当前上下文中。当 :: 前面没有名称时,它指的是全局命名空间。有关详细信息,请参阅最新的 C++ 标准草案中的 [expr.prim.id.qual]