标签: argument-dependent-lookup

Lambdas,本地类型和全局命名空间

这个最小的程序

template <typename X>
void foo (X x)
{
    bar (x);
}

template <typename X>
void bar (X x)
{
}

int main ()
{
    foo ([]{});
}
Run Code Online (Sandbox Code Playgroud)

用gcc编译(4.8.5和5.3)并且无法用clang编译(3.7)

我的分析如下.

bar用于foo和声明之后foo,因此它在foo定义点不可见.barfoo实例化点可以找到唯一的方法是通过参数依赖查找.

双方的唯一参数foo,并bar在规定的拉姆达main.

显然gcc认为它的类型是在全局命名空间中声明的,而clang则没有.因此,gcc可以bar通过ADL和clang找不到.

当我们使用本地定义的类型时会发生同样的事情main:

int main ()
{
    struct K{};
    foo (K());     // gcc compiles, clang complains
}
Run Code Online (Sandbox Code Playgroud)

看起来gcc在这里错了.根据标准的lambda类型是未命名的(expr.prim.lambda/3),因此它不应属于任何名称空间.据推测,本地类型也不应该属于全局命名空间.

分析是否正确?这是一个已知的gcc bug吗?

这个问题的灵感来自于这个问题.

c++ lambda gcc clang argument-dependent-lookup

7
推荐指数
1
解决办法
273
查看次数

为什么在其他函数中声明的函数不参与参数依赖查找?

考虑一个简单的例子:

template <class T>
struct tag { };

int main() {
    auto foo = [](auto x) -> decltype(bar(x)) { return {}; };
    tag<int> bar(tag<int>);
    bar(tag<int>{}); // <- compiles OK
    foo(tag<int>{}); // 'bar' was not declared in this scope ?!
}

tag<int> bar(tag<int>) { return {}; }
Run Code Online (Sandbox Code Playgroud)

[GCC][铛]拒绝编译代码.这段代码在某种程度上是不正确的吗?

c++ templates language-lawyer argument-dependent-lookup c++14

7
推荐指数
2
解决办法
328
查看次数

C++20 中模板的参数依赖查找

下面的程序在 C++20 中编译得很好:

#include <memory>

struct A{ virtual ~A() = default; };
struct B: A {};

int main()
{
    std::shared_ptr<A> p = std::make_shared<B>();
    auto x = dynamic_pointer_cast<A>(p);
}

Run Code Online (Sandbox Code Playgroud)

但是在 C++17 中它会产生一个错误:

<source>: In function 'int main()':
<source>:9:14: error: 'dynamic_pointer_cast' was not declared in this scope; did you mean 'std::dynamic_pointer_cast'?
    9 |     auto x = dynamic_pointer_cast<A>(p);
      |              ^~~~~~~~~~~~~~~~~~~~
      |              std::dynamic_pointer_cast
In file included from /opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/memory:77,
                 from <source>:1:
Run Code Online (Sandbox Code Playgroud)

你能告诉我在 C++20 中有什么改变使它工作吗?

c++ argument-dependent-lookup c++20

7
推荐指数
1
解决办法
137
查看次数

为什么使用 ADL 时 `std::ranges::size` 需要非常量方法?

否则,如果 Ranges::disable_sized_range<std::remove_cv_t<T>> 为 false,则 size(t) 转换为其衰减类型,并且转换后的表达式有效且具有类似整数的类型,其中重载解析通过以下命令执行以下候选人:

  • void size(auto&) = delete;
  • void size(const auto&) = delete; 1
class Test {
    friend size_t size(/*const*/ Test&) {
        return 0;
    }
};

int main() {
    std::ranges::size(Test{});
    // no matching function error when adding the `const` qualifier
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/79e5vrKrT


一般来说,方法size不需要std::size.

为什么会有这样的限制呢std::ranges::size?(好像只有非会员版才能执行。)

c++ argument-dependent-lookup c++20 std-ranges

7
推荐指数
1
解决办法
1562
查看次数

ADL和朋友注射

考虑以下代码:

template <int N>
struct X
{
 friend void f(X *) {}
};

int main()
{
 f((X<0> *)0); // Error?
}
Run Code Online (Sandbox Code Playgroud)

编译器似乎非常不同意.(MSVC08/10表示否,GCC <4.5表示是,但4.5表示否,sun 5.1表示是,intel 11.1表示也是,但是comeau说不(两者都是EDG)).

根据"C++模板 - 完整指南":

...假设一个涉及查找关联类中的朋友的调用实际上导致该类被实例化......虽然这是C++标准编写人员的明确意图,但标准中没有明确规定.

我找不到标准中的相关部分.任何参考?

考虑这种变化:

template <int N>
struct X
{
 template <int M>
 friend void f(X<M> *) {}
};

template <>
struct X<0>
{
};

int main()
{
 X<1>();
 f((X<0> *)0); // Error?
}
Run Code Online (Sandbox Code Playgroud)

这里的关键问题是注入的可行功能是否X<1>应该在ADL期间可见X<0>?它们是否相关?上面提到的所有编译器都接受此代码,但Comeau仅在宽松模式下接受它.不确定标准对此有何看法.

你对此有何看法?

c++ templates friend-function argument-dependent-lookup

6
推荐指数
1
解决办法
1194
查看次数

基于范围的循环和ADL

所述的C++ 0x标准工作草案状态(部分6.5.4)关于开始以下()和()结束,在是隐式的呼叫的范围为基础的循环:

使用参数依赖查找(3.4.2)查找'begin'和'end'.出于此名称查找的目的,名称空间std是关联的名称空间.

我读这个的方式,这意味着为begin()和end()调用设置的重载决议包括以下所有内容:

  • begin()和end()的所有重载都在使用基于范围的for循环的位置的范围内(特别是,全局命名空间中的所有重载都在范围内)
  • 命名空间std中begin()和end()的所有重载
  • 在与其参数关联的其他名称空间中的begin()和end()的所有重载

那是对的吗?

g ++ 4.6的行为似乎与这种解释不一致.对于此代码:

#include <utility>

template <typename T, typename U>
T begin(const std::pair<T, U>& p); 

template <typename T, typename U>
U end(const std::pair<T, U>& p); 

int main()
{
    std::pair<int*, int*> p;
    for (int x : p)
        ;
}
Run Code Online (Sandbox Code Playgroud)

它给出了以下错误:

adl1.cpp: In function 'int main()':
adl1.cpp:12:18: error: No match for 'begin(pair<int *, int *> &)'
adl1.cpp:12:18: candidate is:
/usr/local/lib/gcc/i686-pc-linux-
    gnu/4.6.0/../../../../include/c++/4.6.0/initializer_list:86:38: template<
        class _Tp> constexpr const _Tp * begin(initializer_list<_Tp>)
adl1.cpp:12:18: error: No …
Run Code Online (Sandbox Code Playgroud)

c++ foreach argument-dependent-lookup c++11

6
推荐指数
1
解决办法
1614
查看次数

依赖于参数的查找 - 何时完成,搜索的内容以及如何强制(或阻止)它?

我无法理解依赖于参数(Koenig)查找的规则.

请考虑以下代码:

#include <iostream>

using namespace std;

namespace adl
{
    struct Test { };
    void foo1(Test const &) { cout << "ADL used (foo1)" << endl; }
    void foo2(Test const &) { cout << "ADL used (foo2)" << endl; }
    void foo3(Test const &) { cout << "ADL used (foo3)" << endl; }
}

struct foo1
{
    foo1() { }

    template<class T>
    foo1(T const &) { cout << "ADL not used (foo1)" << endl; }

    template<class T>
    void operator()(T const …
Run Code Online (Sandbox Code Playgroud)

c++ argument-dependent-lookup

6
推荐指数
1
解决办法
357
查看次数

为什么当我不用两个指针调用它时,swap()可以正常工作?

#include <iostream>

using namespace std;

void swap(int *a, int *b) {
    *a = *a^*b;
    *b = *a^*b;
    *a = *a^*b;
}

int main()
{
    int array[]={1,9,2,8,3,7};
    for(int i=0; i<6; i++)
        cout<<array[i];
    cout<<endl;
    swap(array[1], array[4]);
    for(int i=0; i<6;i++)
        cout<<array[i];
    cout<<endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

以上是一个测试样本.我发现如果使用swap(array[1], array[4]);它,它也会交换数组中两个位置的值.但这让我感到困惑,因为函数swap()需要两个指针,而不是两个整数值.

谢谢你的帮助:)

c++ swap namespaces using-directives argument-dependent-lookup

6
推荐指数
4
解决办法
299
查看次数

基于范围的For循环和ADL

这是2011年这个问题的扩展: 基于范围的for循环和ADL

使用Visual Studio 2015,我无法使用Argument Dependent Lookup(ADL)为自定义容器创建基于范围的for循环.

我在下面用一个自定义容器做了一个非常简单的测试用例:

#include <vector>

namespace Foo
{
    template <typename T>
    class Container
    {
    public:

        std::vector<T> values;
    };
}

template <typename T>
typename std::vector<T>::iterator begin(Foo::Container<T>& foo)
{
    return foo.values.begin();
}

template <typename T>
typename std::vector<T>::iterator end(Foo::Container<T>& foo)
{
    return foo.values.end();
}
Run Code Online (Sandbox Code Playgroud)

使用此容器和ADL,以下测试编译完全正常:

int main(int argc, char* argv[])
{
    Foo::Container<int> values;

    for (auto it = begin(values); it != end(values); ++it)
    {
        ...
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

正如它应该.我不确定ADL是否在这里使用,但无论如何,这都是有道理的.从MSDN文档中,我们有:

请记住有关基于范围的这些事实:

  • 自动识别数组.

  • 识别具有.begin()和.end()的容器.

  • 使用依赖于参数的查找begin()和end()用于其他任何事情.

根据我对ADL的理解以及上面的文档,还应该编译以下内容:

int main(int …
Run Code Online (Sandbox Code Playgroud)

c++ visual-c++ argument-dependent-lookup

6
推荐指数
1
解决办法
316
查看次数

该函数调用是否应该模棱两可?

前几天,我偶然发现了这个问题,无法弄清楚哪个答案是正确的,或者都不能接受。

具体来说,我指的是对OtherFunction中的bar(T {})的调用。从我已经能够在编译器资源管理器上进行测试的角度来看,这个决定似乎有些分歧。当gcc和clang编译代码没有问题时,msvc和icc同意它是模棱两可的。

通过与参数相关的查找,隐藏的命名空间中的功能栏变得可见。此外,msvc / icc将全局命名空间中的bar声明视为候选,而gcc / clang则不这样做。似乎不应该考虑全局命名空间中的声明,因为它是在调用bar(T {})之后声明的,但是我不确定我是在正确读取不合格名称查找的规则还是标准是在这方面模棱两可。

https://godbolt.org/z/HAS-Cv

编辑:只要使用/ permissive-选项,看起来msvc已修复此问题(https://devblogs.microsoft.com/cppblog/two-phase-name-lookup-support-comes-to-msvc/

template <typename T>
inline void OtherFunction () {
    bar(T{});
}

namespace hidden {
    struct Foo {};
    inline void bar (Foo foo) {}
}

inline void bar (hidden::Foo foo) {}

void Function () {
    OtherFunction<hidden::Foo>();
}
Run Code Online (Sandbox Code Playgroud)

c++ function-templates name-lookup argument-dependent-lookup

6
推荐指数
1
解决办法
116
查看次数