Skip to the content.

ADL(Argument-Dependent Lookup,Koenig Lookup)

namespace jc {

struct A {};
struct B {};
void f1(int) {}
void f2(A) {}

}  // namespace jc

namespace jd {

void f1(int i) {
  f1(i);  // 调用 jd::f1(),造成无限递归
}

void f2(jc::A t) {
  f2(t);  // 通过 t 的类型 jc::A 看到 jc,通过 jc 看到 jc::f2()
          // 因为 jd::f2() 也可见,此处产生二义性调用错误
}

void f3(jc::B t) {
  f3(t);  // 通过 t 的类型 jc::B 看到 jc,但 jc 中无 jc::f3()
          // 此处调用 jd::f3(),造成无限递归
}

}  // namespace jd

int main() {}
namespace jc {

int x;

struct Base {
  int i;
};

struct Derived : Base {};

void f(Derived* p) {
  p->i = 0;        // 找到 Base::i
  Derived::x = 0;  // 错误:在受限作用域中找不到 ::x
}

}  // namespace jc

int main() {}
namespace jc {

extern int x;  // 1

int f(int x) {  // 2
  if (x < 0) {
    int x = 1;  // 3
    f(x);       // 使用 3
  }
  return x + ::x;  // 分别使用 2、1
}

}  // namespace jc

int main() {}
#include <iostream>
#include <string>

namespace jc {

struct A {};

void f(const A&) {}  // f() 是 A 的逻辑组成部分

}  // namespace jc

jc::A a;

int main() {
  f(a);  // 通过 ADL 找到 jc::f(),如果没有 ADL,就要写成 jc::f(a)
  std::string s;
  std::cout << s;  // std::operator<<() 是 std::string 的逻辑组成部分
  // 如果没有 ADL,就要写成 std::operator<<(std::cout, s)
}
namespace jc {

class A {};

template <typename>
void f(A*) {}

}  // namespace jc

void g(jc::A* p) {
  f<int>(p);  // 错误,不知道 f<int> 是函数,所以不知道 p 是实参,不会用 ADL
}

int main() {}
namespace jc {

template <typename T>
constexpr int f(T) {
  return 1;
}

}  // namespace jc

namespace jd {

using namespace jc;  // 忽略 using 声明,不会调用 jc::f

enum Color { red };
constexpr int f(Color) { return 2; }

}  // namespace jd

constexpr int f(int) { return 3; }

static_assert(::f(jd::red) == 3);  // 受限的函数名称,不使用 ADL
static_assert(f(jd::red) == 2);    // 使用 ADL 找到 jd::f()

int main() {}
namespace jc {

template <typename T>
class A {
  friend void f() {}
  friend void f(A<T>) {}
};

void g(const A<int>& a) {
  f();   // f() 无参数,不能使用 ADL,不可见
  f(a);  // f(A<int>) 关联类 A<int> 所以可见,若类 A<int> 未实例化则调用时实例化
}

}  // namespace jc

int main() {}

注入类名(Injected Class Name)

namespace jc {

int A;

struct A {
  void f() {
    A* p;    // OK:A 是注入类名
    ::A* q;  // 错误:查找到变量名 A,隐藏了 struct A 的名称
  }
};

}  // namespace jc

int main() {}
namespace jc {

template <template <typename> class>
struct A {};

template <typename T>
struct B {
  B* a;            // B 被当作类型名,等价于 B<T>
  B<void>* b;      // B 被当作模板名
  using c = A<B>;  // B 被当作模板名
  A<jc::B> d;      // jc::B 不是注入类名,总会被当作模板名
};

}  // namespace jc

int main() {}

非模板中的上下文相关性

identifier, type, x
symbol, *
identifier, nontype, x
symbol, *
namespace jc {

template <bool B>
struct A {
  static const bool value = B;
};

static_assert(A<(1 > 0)>::value);  // 必须使用小括号

}  // namespace jc

int main() {}

Dependent name

当前实例化(current instantiation)和未知特化(unknown specialization)

namespace jc {

template <typename T>
struct A {
  using type = T;

  A* a;        // A 是当前实例化
  A<type>* b;  // A<type> 是当前实例化
  A<T*>* c;    // A<T*> 是未知特化

  struct B {
    A* a;        // A 是当前实例化
    A<type>* b;  // A<type> 是当前实例化
    B* c;        // B 是当前实例化
  };

  struct C {
    A* a;        // A 是当前实例化
    A<type>* b;  // A<type> 是当前实例化
    B* c;        // 不在 B 的作用域内,B 是未知特化
    C* d;        // C 是当前实例化
  };
};

template <>
struct A<int>::B {
  int i;
};

}  // namespace jc

int main() {
  jc::A<double>::C{}.c->a;
  jc::A<int>::C{}.c->i;  // 使用特化的 A<int>::B
}

typename 消歧义符

namespace jc {

template <typename T>
struct A {
  static constexpr int x = 0;  // x 是值
};

template <typename T>
struct B {
  int y;

  void f() {
    A<T>::x* y;  // 默认被看作乘法表达式
  }
};

template <>
struct A<int> {
  using x = int;  // x 是类型
};

}  // namespace jc

int main() {
  jc::B<int>{}.f();   // A<int>::x* y 是声明,int* y
  jc::B<void>{}.f();  // A<void>::x* y 是乘法,0 * y
}
namespace jc {

template <typename T>
struct A {
  static constexpr int x = 0;  // x 是值
};

template <typename T>
struct B {
  int y;

  void f() {
    typename A<T>::x* y;  // 默认被看作声明
  }
};

template <>
struct A<int> {
  using x = int;  // x 是类型
};

}  // namespace jc

int main() {
  jc::B<int>{}.f();   // A<int>::x* y 是声明,int* y
  jc::B<void>{}.f();  // A<void>::x* y 是乘法,0 * y
}
namespace jc {

struct Base {
  int i;
};

template <typename T>
struct A {
  using type = T;
};

template <typename T>
struct Derived : A<T>::type {  // 基类列表中不能加 typename 消歧义符
  Derived()
      : A<T>::type  // 初始化列表中不能加 typename 消歧义符
        (typename A<T>::type{0})  // 必须加 typename 消歧义符
  {}

  A<T> f() {
    typename A<T>::type* p;  // 必须加 typename 消歧义符
    return {};
  }

  A<int>::type* s;  // non-dependent name,typename 消歧义符可有可无
};

}  // namespace jc

int main() { jc::Derived<jc::Base>{}.f(); }

template 消歧义符

namespace jc {

template <typename T>
struct A {
  template <typename U>
  struct Impl {
    template <typename Y>
    static void f() {}
  };

  template <typename U>
  static void f() {}
};

}  // namespace jc

template <typename T>
void test() {
  T::template Impl<T>::template f<T>();
  T::template f<T>();
}

int main() { test<jc::A<int>>(); }

Non-dependent base

#include <type_traits>

namespace jc {

template <typename>
struct Base {
  using T = char;
};

template <typename T>
struct Derived1 : Base<void> {  // non-dependent base
  using type = T;               // T 是 Base<void>::T
};

template <typename T>
struct Derived2 : Base<T> {  // dependent base
  using type = T;            // T 是模板参数
};

static_assert(std::is_same_v<Derived1<int>::type, char>);
static_assert(std::is_same_v<Derived2<int>::type, int>);

}  // namespace jc

int main() {}

Dependent base

namespace jc {

template <typename>
struct Base {
  static constexpr int value = 1;
};

template <typename T>
struct Derived : Base<T> {  // dependent base
  constexpr int get_value() const {
    return value;  // 错误:不会在 dependent base 中查找 non-dependent name
  }
};

}  // namespace jc

int main() {}
namespace jc {

template <typename>
struct Base {
  static constexpr int value = 1;
};

template <typename T>
struct Derived : Base<T> {  // dependent base
  constexpr int get_value() const {
    return this->value;  // dependent name,会在 dependent base 中查找
  }
};

template <>
struct Base<bool> {
  static constexpr int value = 2;
};

}  // namespace jc

int main() {
  static_assert(jc::Derived<int>{}.get_value() == 1);
  static_assert(jc::Derived<bool>{}.get_value() == 2);
}
namespace jc {

template <typename>
struct Base {
  static constexpr int value = 1;
};

template <typename T>
struct Derived : Base<T> {  // dependent base
  using Base<T>::value;

  constexpr int get_value() const {
    return value;  // dependent name,会在 dependent base 中查找
  }
};

template <>
struct Base<bool> {
  static constexpr int value = 2;
};

}  // namespace jc

int main() {
  static_assert(jc::Derived<int>{}.get_value() == 1);
  static_assert(jc::Derived<bool>{}.get_value() == 2);
}
#include <cassert>

namespace jc {

template <typename>
struct Base {
  virtual int f() const { return 1; }
};

template <typename T>
struct Derived : Base<T> {  // dependent base
  virtual int f() const { return 2; }
  int get_value() const { return Base<T>::f(); }
};

template <>
struct Base<bool> {
  virtual int f() const { return 3; }
};

}  // namespace jc

int main() {
  assert(jc::Derived<int>{}.get_value() == 1);
  assert(jc::Derived<bool>{}.get_value() == 3);
}
#include <cassert>

namespace jc {

template <typename>
struct Base {
  virtual int f() const { return 1; }
};

template <typename T>
struct Derived1 : Base<T> {  // dependent base
  virtual int f() const { return 2; }
  int get_value() const { return this->f(); }
};

template <typename T>
struct Derived2 : Base<T> {  // dependent base
  using Base<T>::f;
  virtual int f() const { return 2; }
  int get_value() const { return f(); }
};

template <>
struct Base<bool> {
  virtual int f() const { return 3; }
};

}  // namespace jc

int main() {
  assert(jc::Derived1<int>{}.get_value() == 2);
  assert(jc::Derived1<bool>{}.get_value() == 2);
  assert(jc::Derived2<int>{}.get_value() == 2);
  assert(jc::Derived2<bool>{}.get_value() == 2);
}