首页 > 解决方案 > “std::transform”在多个编译器上编译时没有限定名称查找?

问题描述

我正在用 C++ 编写一个库,当时我发现调用std::transform意外地编译得很好,而没有完全限定具有std::命名空间前缀的调用。根据 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 示例

铿锵的例子

MSVC 示例

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

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

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

标签: c++gccvisual-c++namespacesclang

解决方案


不,这不是错误1 ​​。这是依赖于参数的查找(又名 Koenig 查找)。

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

在这种情况下,这种关系可能并不明显,但函数的参数是v.begin()返回值,类似于std::vector<int>::iterator2,因此编译器std也会在命名空间中查找函数。


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

推荐阅读