“인수 종속 조회”(일명 ADL 또는“Koenig 조회”) 란 무엇입니까?


176

인수 종속 조회가 무엇인지에 대한 좋은 설명은 무엇입니까? 많은 사람들이이를 Koenig Lookup이라고도합니다.

바람직하게는 알고 싶습니다.

  • 왜 좋은가요?
  • 왜 나쁜 일입니까?
  • 어떻게 작동합니까?




답변:


223

Koenig Lookup 또는 Argument Dependent Lookup 은 C ++에서 컴파일러가 규정되지 않은 이름을 찾는 방법을 설명합니다.

C ++ 11 표준 § 3.4.2 / 1 상태는 다음과 같습니다.

함수 호출 (5.2.2)의 접미사 표현식이 규정되지 않은 ID 인 경우, 정규 규정되지 않은 검색 (3.4.1) 중에 고려되지 않은 다른 네임 스페이스가 검색 될 수 있으며, 이러한 네임 스페이스에서 네임 스페이스 범위 친구 함수 선언 ( 11.3) 그렇지 않으면 보이지 않을 수 있습니다. 검색에 대한 이러한 수정은 인수 유형 (및 템플리트 템플리트 인수의 경우 템플리트 인수의 네임 스페이스)에 따라 다릅니다.

간단한 용어로 Nicolai Josuttis는 1을 말합니다 .

함수의 네임 스페이스에 하나 이상의 인수 유형이 정의 된 경우 함수의 네임 스페이스를 규정 할 필요가 없습니다.

간단한 코드 예제 :

namespace MyNamespace
{
    class MyClass {};
    void doSomething(MyClass);
}

MyNamespace::MyClass obj; // global object


int main()
{
    doSomething(obj); // Works Fine - MyNamespace::doSomething() is called.
}

위의 예제에는 using선언이나 지시문이 using없지만 컴파일러 doSomething()Koenig 조회MyNamespace 를 적용하여 네임 스페이스 에 선언 된 함수로 규정되지 않은 이름 을 올바르게 식별합니다 .

어떻게 작동합니까?

이 알고리즘은 컴파일러에게 로컬 범위뿐만 아니라 인수 유형이 포함 된 네임 스페이스도 확인하도록 지시합니다. 따라서 위 코드에서 컴파일러는 obj함수의 인수 인 객체 doSomething()가 네임 스페이스에 속하는 것을 발견합니다 MyNamespace. 따라서 해당 네임 스페이스를보고의 선언을 찾습니다 doSomething().

Koenig 조회의 장점은 무엇입니까?

위의 간단한 코드 예제에서 알 수 있듯이 Koenig 조회는 프로그래머에게 편의성과 사용 편의성을 제공합니다. Koenig 조회가 없으면 정규화 된 이름을 반복적으로 지정하거나 수많은 using선언을 사용하기 위해 프로그래머에게 오버 헤드가 발생합니다 .

Koenig 조회에 대한 비판이 필요한 이유는 무엇입니까?

Koenig 조회에 대한 과도한 의존은 시맨틱 문제로 이어질 수 있으며 때때로 프로그래머를 보호합니다.

std::swap두 개의 값을 바꾸는 표준 라이브러리 알고리즘 인의 예를 고려하십시오 . Koenig 조회를 사용하면 다음과 같은 이유로이 알고리즘을 사용할 때주의해야합니다.

std::swap(obj1,obj2);

다음과 같은 동작을 나타내지 않을 수 있습니다.

using std::swap;
swap(obj1, obj2);

ADL의 경우 어떤 버전의 swap함수가 호출되는지는 전달 된 인수의 네임 스페이스에 따라 다릅니다.

거기에 네임 스페이스를 존재하는 경우 A와 경우 A::obj1, A::obj2& A::swap()존재하는 다음 두 번째 예를 호출 발생합니다 A::swap()사용자가 원하는 것을하지 않을 수도 있습니다.

또한, 어떤 이유로 두 경우 A::swap(A::MyClass&, A::MyClass&)std::swap(A::MyClass&, A::MyClass&)정의, 후 첫 번째 예는 호출 std::swap(A::MyClass&, A::MyClass&)때문이 아니라 두 번째는 컴파일되지 않습니다 swap(obj1, obj2)모호 할 것이다.

하찮은 일:

"Koenig 조회"라고하는 이유는 무엇입니까?

전 AT & T와 Bell Labs의 연구원이자 프로그래머 인 Andrew Koenig에 의해 고안 되었기 때문 입니다.

더 읽을 거리 :


1 Koenig 조회의 정의는 Josuttis의 저서 인 The C ++ Standard Library : A Tutorial and Reference에 정의되어 있습니다.


11
@ AlokSave : 답변에 +1하지만 퀴즈가 정확하지 않습니다. Koenig는 여기에서 고백하면서 ADL을 발명하지 않았습니다 :)
legends2k

20
Koenig 알고리즘에 대한 비판의 예는 "con"만큼 Koenig 조회의 "기능"으로 간주 될 수 있습니다. 이러한 방식으로 std :: swap ()을 사용하는 것이 일반적인 관용구입니다.보다 전문적인 버전 A :: swap ()이 제공되지 않는 경우 'std :: swap () 사용'을 제공하십시오. 특수한 버전의 A :: swap ()을 사용할 수있는 경우 일반적으로 해당 버전을 호출 하려고 합니다. 이것은 컴파일과 작업에 대한 호출을 신뢰할 수 있기 때문에 swap () 호출에 대한 더 일반적인 점을 제공하지만, 더 전문화 된 버전이있는 경우 사용할 수 있습니다.
Anthony Hall

6
@anthrond 이것에 더 많은 것이 있습니다. 함께 std::swap유일한 대안은 추가하는 것이기 때문에 실제로 그렇게해야 std::swap당신을위한 템플릿 기능을 명시 적으로 전문화를 A클래스입니다. 그러나 A클래스 자체가 템플릿이라면 명시적인 전문화가 아닌 부분적인 전문화가됩니다. 템플릿 기능의 일부 특수화는 허용되지 않습니다. 오버로드를 추가하는 std::swap것이 대안이지만 명시 적으로 금지되어 있습니다 ( std네임 스페이스 에 항목을 추가 할 수 없음 ). 따라서 ADL이 유일한 방법입니다 std::swap.
Adam Badura

1
"koenig 조회의 장점"에서 오버로드 된 연산자에 대한 언급을 기대했을 것입니다. 예제 std::swap()는 약간 거꾸로 보입니다. std::swap()유형에 특정한 과부하가 아닌를 선택 하면 문제가 발생할 것으로 예상합니다 A::swap(). 의 예 std::swap(A::MyClass&, A::MyClass&)는 오해의 소지가 있습니다. 이후 std사용자 유형에 대한 특정 과부하를하지 않을 것, 나는 그것이 좋은 예라고 생각하지 않습니다.
Arvid

1
@gsamaras ... 그리고? 우리는 함수가 정의되지 않았다는 것을 모두 알 수 있습니다. 오류 메시지는 실제로 MyNamespace::doSomething뿐만 아니라 찾고 있기 때문에 실제로 작동했음을 증명합니다 ::doSomething.
Fund Monica의 소송

69

Koenig Lookup에서 네임 스페이스를 지정하지 않고 함수를 호출하면 함수의 이름 인수의 유형이 정의 된 네임 스페이스에서 검색됩니다. 그것은 또한으로 알려져 있습니다 이유입니다 인수 종속 이름 조회 짧은 단지로, ADL .

Koenig 조회로 인해 다음과 같이 작성할 수 있습니다.

std::cout << "Hello World!" << "\n";

그렇지 않으면 다음과 같이 작성해야합니다.

std::operator<<(std::operator<<(std::cout, "Hello World!"), "\n");

실제로 너무 많이 입력하고 코드가 정말 못 생겼습니다!

다시 말해 Koenig Lookup이 없으면 Hello World 프로그램 조차 복잡해 보입니다.


12
설득력있는 예.
Anthony Hall

10
@AdamBadura : std::coutADL을 활성화하기에 충분한 함수에 대한 하나의 인수입니다. 그거 알아?
Nawaz

1
@meet : 귀하의 질문에는이 공간에서 제공 할 수없는 긴 답변이 필요합니다. 따라서 나는 다음과 같은 주제에 대해서만 읽을 것을 권유 할 수 있습니다 ostream<<. 2) 정규화 된 이름 (예 : std::vector또는 std::operator<<). 3) Argument Dependent Lookup에 대한보다 자세한 연구.
Nawaz

2
@WorldSEnder : 그렇습니다. std::endl인수로 취할 수있는 함수 는 실제로 멤버 함수입니다. 어쨌든, "\n"대신에 사용하면 std::endl내 대답이 정확합니다. 의견 주셔서 감사합니다.
Nawaz

2
@Destructor : 형식의 함수 f(a,b)호출은 무료 함수 를 호출하기 때문 입니다. 따라서의 경우 두 번째 인수로 사용 std::operator<<(std::cout, std::endl);되는 무료 기능이 없습니다 std::endl. std::endl인수로 사용하고 작성해야하는 멤버 함수입니다 std::cout.operator<<(std::endl);. 그리고 두 번째 인수로 사용 되는 자유 함수 가 있기 때문에 작동합니다. 잘 작동합니다. char const*"\n"'\n'
Nawaz

30

어쩌면 그 이유부터 시작하는 것이 가장 좋을 것입니다.

네임 스페이스가 도입되었을 때, 별도의 라이브러리가 서로 간섭하지 않도록 네임 스페이스에 모든 것을 정의하는 것이 아이디어였습니다. 그러나 이것은 운영자에게 문제를 일으켰습니다. 예를 들어 다음 코드를보십시오.

namespace N
{
  class X {};
  void f(X);
  X& operator++(X&);
}

int main()
{
  // define an object of type X
  N::X x;

  // apply f to it
  N::f(x);

  // apply operator++ to it
  ???
}

물론 당신은 쓸 수 N::operator++(x)있었지만, 그것은 연산자 오버로드의 전체 지점을 물리 쳤을 것입니다. 따라서 컴파일러가 operator++(X&)범위 내에 있지 않다는 사실에도 불구하고 컴파일러를 찾을 수있는 솔루션을 찾아야 했습니다. 반면에 operator++, 호출을 모호하게 할 수있는 다른 관련없는 네임 스페이스에 정의 된 다른 것을 찾지 않아야 합니다 (이 간단한 예에서는 모호함이 없지만보다 복잡한 예에서는 그렇습니다). 해결책은 인수에 의존하기 때문에 (더 정확하게는 인수 유형에 따라) ARL (Argument Dependent Lookup)이었습니다. 이 계획은 Andrew R. Koenig에 의해 발명되었으므로 종종 Koenig 조회라고도합니다.

트릭은 함수 호출의 경우 일반 이름 조회 (사용 시점에서 범위에서 이름을 찾는 것) 외에도 함수에 지정된 인수 유형의 범위에서 두 번째 조회를 수행한다는 것입니다. 당신이 쓰는 경우에 따라서 위의 예에서 x++주, 그것은을 찾습니다 operator++전역 범위에 있지만, 추가의 유형이 범위뿐만 아니라 x, N::X정의 된, 즉,에 namespace N. 그리고 거기에서 일치하는 것을 발견 operator++하므로 x++작동합니다. 또 operator++다른 네임 스페이스에 정의는, 말 N2, 그러나 찾을 수 없습니다. ADL은 네임 스페이스로 제한되지 않기 때문에 in f(x)대신에 사용할 수도 있습니다 .N::f(x)main()


감사! 왜 그것이 존재하는지 이해하지 못했습니다!
user965369

20

내 의견으로는 그것에 관한 모든 것이 좋지는 않습니다. 컴파일러 공급 업체를 포함한 사람들은 때때로 불행한 행동으로 인해이를 모욕하고 있습니다.

ADL은 C ++ 11에서 for-range 루프를 대대적으로 검사합니다. ADL이 의도하지 않은 결과를 초래할 수있는 이유를 이해하려면 인수가 정의 된 네임 스페이스뿐만 아니라 인수의 템플리트 인수, 함수 유형의 매개 변수 유형 / 포인터 유형의 포인터 유형의 인수도 고려하십시오. 등등.

부스트를 사용하는 예

std::vector<boost::shared_ptr<int>> v;
auto x = begin(v);

사용자가 boost.range 라이브러리를 사용하는 경우 std::begin(ADL을 사용하여 std::vector) boost::begin찾 거나 (ADL을 사용하여 ) 찾게 되므로 모호한 결과가 발생했습니다 boost::shared_ptr.


저는 항상 템플릿 인수를 고려할 때 어떤 이점이 있는지 궁금했습니다.
Dennis Zickefoose

ADL이 운영자에게만 권장되고 다른 함수에 대해 네임 스페이스를 명시 적으로 작성하는 것이 더 낫다고 말하는 것이 공정합니까?
balki

또한 기본 인수 클래스의 네임 스페이스도 고려합니까? (물론 그렇게되면 화를 낼 것입니다).
Alex B

3
어떻게 고치는 지? 표준 사용 : 시작?
paulm

2
@paulm 예, std::begin네임 스페이스 모호성을 지 웁니다.
Nikos
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.