标签: argument-dependent-lookup

什么是"Argument-Dependent Lookup"(又名ADL或"Koenig Lookup")?

什么是关于什么参数依赖查找的好解释?很多人也称它为Koenig Lookup.

我最好知道:

  • 为什么这是好事?
  • 为什么这是一件坏事?
  • 它是如何工作的?

c++ c++-faq name-lookup argument-dependent-lookup

163
推荐指数
4
解决办法
3万
查看次数

Bjarne对这个ADL的例子是错误的,还是我有编译器错误?

我正在阅读C++编程语言,第4版(由Bjarne Stroustrup撰写)关于.这是引用(26.3.6,Overaggressive ADL):

依赖于参数的查找(通常称为ADL)对于避免冗长非常有用(14.2.4).例如:

#include <iostream>

int main()
{
    std::cout << "Hello, world" << endl; // OK because of ADL
}
Run Code Online (Sandbox Code Playgroud)

如果没有依赖于参数的查找,则endl无法找到操纵器.实际上,编译器注意到第一个参数<<ostream定义的std.因此,寻找endlstd和发现它(中<iostream>).

这是编译器产生的结果(C++ 11模式):

prog.cpp: In function ‘int main()’:
prog.cpp:4:36: error: ‘endl’ was not declared in this scope
 std::cout << "Hello, world" << endl;
                                ^
Run Code Online (Sandbox Code Playgroud)

这是编译器或书中的错误.标准说什么?

更新:

我需要澄清一下.我知道正确的答案是使用std::endl.问题是关于书中的文字.正如Lachlan Easton所说,这不仅仅是一个错字.整段是(可能)错了.如果这本书是由另一位(鲜为人知的)作者写的,我可以接受这种错误,但我(并且仍然)怀疑,因为它是由Bjarne写的.

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

80
推荐指数
5
解决办法
3382
查看次数

为什么ADL没有找到功能模板?

C++规范的哪一部分限制参数依赖查找在相关命名空间集合中查找函数模板?换句话说,为什么main下面的最后一次调用无法编译?

namespace ns {
    struct foo {};
    template<int i> void frob(foo const&) {}
    void non_template(foo const&) {}
}

int main() {
    ns::foo f;
    non_template(f); // This is fine.
    frob<0>(f); // This is not.
}
Run Code Online (Sandbox Code Playgroud)

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

79
推荐指数
3
解决办法
3825
查看次数

自定义容器应该有免费的开始/结束功能吗?

当创建一个按照通常规则播放的自定义容器类(即使用STL算法,使用性能良好的通用代码等)时,在C++ 03中实现迭代器支持和成员开始/结束函数就足够了.

C++ 11引入了两个新概念 - 基于范围的for循环和std :: begin/end.基于范围的for循环理解成员开始/结束函数,因此任何C++ 03容器都支持基于范围的开箱即用.对于算法,推荐的方法(根据Herb Sutter的'Writing modern C++ code')是使用std :: begin而不是member function.

但是,此时我不得不问 - 是否建议调用完全限定的begin()函数(即std :: begin(c))或依赖ADL并调用begin(c)?

在这种特殊情况下,ADL似乎毫无用处 - 因为如果可能的话,std :: begin(c)委托给c.begin(),通常的ADL好处似乎不适用.如果每个人都开始依赖ADL,那么所有自定义容器都必须在其必需的命名空间中实现额外的begin()/ end()自由函数.但是,有几个消息来源似乎暗示对开始/结束的不合格调用是推荐的方式(即https://svn.boost.org/trac/boost/ticket/6357).

那么C++ 11的方式是什么?容器库作者是否应该为其类编写额外的开始/结束函数,以便在没有使用namespace std的情况下支持不合格的开始/结束调用; 或者使用std :: begin;?

c++ containers iterator argument-dependent-lookup c++11

58
推荐指数
1
解决办法
4928
查看次数

ADL的缺陷是什么?

前段时间我读了一篇文章解释了参数依赖查找的几个缺陷,但我再也找不到了.它是关于获取您不应该访问的东西或类似的东西.所以我想我会在这里问:ADL的缺陷是什么?

c++ namespaces overload-resolution argument-dependent-lookup

50
推荐指数
2
解决办法
4053
查看次数

如何编写启用ADL的尾随返回类型或noexcept规范?

想象一下,我正在写一些容器模板或其他东西.现在是时候专注std::swap于它了.作为一个好公民,我会通过这样的方式启用ADL:

template <typename T>
void swap(my_template<T>& x, my_template<T>& y) {
    using std::swap;
    swap(x.something_that_is_a_T, y.something_that_is_a_T);
}
Run Code Online (Sandbox Code Playgroud)

这非常整洁.直到我想添加一个异常规范.我swapnoexcept只要调换Tnoexcept.所以,我会写一些类似的东西:

template <typename T>
void swap(my_template<T>& x, my_template<T>& y)
    noexcept(noexcept(swap(std::declval<T>(), std::declval<T>())))
Run Code Online (Sandbox Code Playgroud)

问题是,swap在那里需要ADL发现swapstd::swap.我该如何处理?

c++ noexcept argument-dependent-lookup c++11

46
推荐指数
3
解决办法
1151
查看次数

可以定义一个完全通用的swap()函数吗?

以下片段:

#include <memory>
#include <utility>

namespace foo
{
    template <typename T>
    void swap(T& a, T& b)
    {
        T tmp = std::move(a);
        a = std::move(b);
        b = std::move(tmp);
    }

    struct bar { };
}

void baz()
{
    std::unique_ptr<foo::bar> ptr;
    ptr.reset();
}
Run Code Online (Sandbox Code Playgroud)

不为我编译:

$ g++ -std=c++11 -c foo.cpp
In file included from /usr/include/c++/5.3.0/memory:81:0,
                 from foo.cpp:1:
/usr/include/c++/5.3.0/bits/unique_ptr.h: In instantiation of ‘void std::unique_ptr<_Tp, _Dp>::reset(std::unique_ptr<_Tp, _Dp>::pointer) [with _Tp = foo::bar; _Dp = std::default_delete<foo::bar>; std::unique_ptr<_Tp, _Dp>::pointer = foo::bar*]’:
foo.cpp:20:15:   required from here
/usr/include/c++/5.3.0/bits/unique_ptr.h:342:6: error: call of …
Run Code Online (Sandbox Code Playgroud)

c++ gcc libstdc++ argument-dependent-lookup c++11

39
推荐指数
3
解决办法
2112
查看次数

iter_swap有什么意义?

我只是想知道,为什么有人写这个:

std::iter_swap(i, k);
Run Code Online (Sandbox Code Playgroud)

而不是这个?

std::swap(*i, *k);   // saved a few keystrokes!
Run Code Online (Sandbox Code Playgroud)

然后我查看了实现iter_swap,当然它只使用swap而不是std::swap因为我们已经在namespace std,但无论如何.这引出了我的下一个问题:

为什么有人写这个:

using std::swap;
swap(a, b);
Run Code Online (Sandbox Code Playgroud)

而不是这个?

std::iter_swap(&a, &b);   // saved an entire line of code!
Run Code Online (Sandbox Code Playgroud)

我在这里忽略了重要的差异/问题吗?

c++ templates swap namespaces argument-dependent-lookup

34
推荐指数
2
解决办法
2013
查看次数

带名称空间的编译器的有趣行为

假设以下代码:

#include <iostream>
using namespace std;

namespace X
{
  class A{};

  void f(A a){}

  void g(int a){}
}

int main()
{
  X::A a;
  f(a);
  g(5);
}
Run Code Online (Sandbox Code Playgroud)

编译代码时,会发生以下编译错误:

main.cpp:在函数'int main()'中:
main.cpp:error:'g'未在此范围内声明

所以函数f编译得很完美,但事实g并非如此.怎么样?它们都属于同一名称空间.编译器是否从类型的参数中推断出该函数f属于X命名空间X::A?在这种情况下编译器如何表现?

c++ namespaces compiler-errors argument-dependent-lookup

32
推荐指数
3
解决办法
1169
查看次数

C++ 编译时间计数器,重温

TL; 博士

在您尝试阅读整篇文章之前,请了解:

  1. 我自己已经找到了解决所提出问题的方法,但我仍然很想知道分析是否正确;
  2. 我已将解决方案打包到一个fameta::counter类中,以解决一些剩余的怪癖。你可以在 github 上找到它
  3. 你可以在 Godbolt 上看到它。

一切是如何开始的

自从 Filip Roséen 在 2015 年发现/发明了通过友元注入编译时间计数器的黑魔法是在 C++ 中,我一直对这个设备有点着迷,所以当 CWG决定功能必须去时,我很失望,但仍然充满希望可以通过向他们展示一些引人注目的用例来改变他们的想法。

然后,几年前,我决定再看一遍,以便uberswitch es可以嵌套 - 在我看来,这是一个有趣的用例 - 只是发现它不再适用于新版本的可用的编译器,即使问题 2118是(现在仍然是)处于打开状态:代码会编译,但计数器不会增加。

该问题已在 Roséen 的网站和最近的 stackoverflow 上报告:Does C++ support compile-time counters?

几天前,我决定再次尝试解决这些问题

我想了解编译器发生了什么变化,使看似仍然有效的 C++ 不再起作用。为此,我在互联网上广泛搜索,寻找有人谈论它,但无济于事。所以我开始尝试并得出了一些结论,我在这里提出这些结论是希望能从这里的知识渊博的人那里得到反馈。

为了清楚起见,我在下面展示了 Roséen 的原始代码。有关其工作原理的说明,请参阅他的网站

template<int N>
struct flag {
  friend constexpr int adl_flag …
Run Code Online (Sandbox Code Playgroud)

c++ counter friend-function argument-dependent-lookup constexpr

32
推荐指数
1
解决办法
6506
查看次数