【问题标题】:"std::transform" compiles without qualified name lookup on multiple compilers? [duplicate]“std::transform”在多个编译器上编译时没有限定名称查找? [复制]
【发布时间】:2021-01-31 12:25:47
【问题描述】:

当我发现对std::transform 的调用没有完全限定具有std:: 命名空间前缀的调用时,我正在用C++ 编写一个库。根据 C++ 文档,std::transform 是在 std:: 命名空间中定义的,因此如果没有完全限定名称,则不应编译。

#include <algorithm>
#include <vector>

int main()
{
    std::vector<int> v{ 1, 2, 3 };

    // "transform" is supposed to be in the namespace "std::"???
    transform(v.begin(), v.end(), v.begin(), [](const auto& value) {
        return value + 1;
        });
}

起初我认为这是标准库的 Microsoft 实现中的一个错误,因为我在 Visual Studio 中工作,但后来我在 https://godbolt.org/ 上使用一堆不同的编译器对其进行了测试,它似乎编译没有错误也可以在其他编译器上使用!

gcc example

clang example

MSVC example

transform 调用更改为::transform 会导致编译失败,因此很明显全局命名空间中没有transform 的符号。

我的猜测是,在 &lt;algorithm&gt; 头文件的某个地方,有人不小心在全局命名空间中键入了 using std::transform;,这将使函数可以在没有 std:: 前缀的情况下调用......但这将被认为是不好的做法,并且会是标准库实现中的一个错误,不是吗?

我是不是在多个编译器的标准库实现中发现了一个错误!?如果是这样,我什至会如何报告这样的错误?

【问题讨论】:

  • 它被称为“参数依赖查找”。在与任何函数参数关联的命名空间中查找未限定的函数名称。在这种情况下,v.begin() 有一些迭代器类型 std:: something 。这就是重载运算符调用的工作原理

标签: c++ gcc visual-c++ namespaces clang


【解决方案1】:

不,这不是错误1。这是argument dependent lookup(又名 Koenig 查找)。

当函数的参数位于特定命名空间中时,编译器将在该命名空间中查找函数本身。

在这种情况下,关系可能不明显,但函数的参数是v.begin()返回的,类似于std::vector&lt;int&gt;::iterator2,所以编译器在命名空间@中查找987654324@的功能也是如此。


1. 然而,这是非常出乎意料的行为,有些人不仅会,而且认为这是语言定义中的错误。
2. 但这可能不是它的确切名称。向量具有相同的迭代器类型很有用,即使它们具有不同的分配器类型,并且要做到这一点,迭代器类型通常会在向量之外定义。

【讨论】:

  • 天啊!我当然知道,但我什至没有想到 ADL,这似乎太出乎意料了!绝对是 C++ 比较晦涩的特性之一哈哈
  • ADL 对于std::cout &lt;&lt; "Hello, world\n"; 之类的东西很重要。如果没有它,您将需要其他方式来告诉编译器&lt;&lt; 是在命名空间std 中定义的。使用 ADL,它会在 std 中查找,因为在那里定义了 std::cout。这是 ADL 的原始用例,没有人预见到使其普遍应用会出现问题。事后看来,有些人认为它应该仅限于运营商。
猜你喜欢
  • 2021-09-14
  • 2012-10-06
  • 2011-05-23
  • 1970-01-01
  • 2016-02-07
  • 1970-01-01
  • 1970-01-01
  • 2022-01-17
相关资源
最近更新 更多