인수 종속 조회가 무엇인지에 대한 좋은 설명은 무엇입니까? 많은 사람들이이를 Koenig Lookup이라고도합니다.
바람직하게는 알고 싶습니다.
- 왜 좋은가요?
- 왜 나쁜 일입니까?
- 어떻게 작동합니까?
인수 종속 조회가 무엇인지에 대한 좋은 설명은 무엇입니까? 많은 사람들이이를 Koenig Lookup이라고도합니다.
바람직하게는 알고 싶습니다.
답변:
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 조회가 없으면 정규화 된 이름을 반복적으로 지정하거나 수많은 using
선언을 사용하기 위해 프로그래머에게 오버 헤드가 발생합니다 .
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)
모호 할 것이다.
전 AT & T와 Bell Labs의 연구원이자 프로그래머 인 Andrew Koenig에 의해 고안 되었기 때문 입니다.
표준 C ++ 03 / 11 [basic.lookup.argdep] : 3.4.2 인수에 따른 이름 조회.
1 Koenig 조회의 정의는 Josuttis의 저서 인 The C ++ Standard Library : A Tutorial and Reference에 정의되어 있습니다.
std::swap
유일한 대안은 추가하는 것이기 때문에 실제로 그렇게해야 std::swap
당신을위한 템플릿 기능을 명시 적으로 전문화를 A
클래스입니다. 그러나 A
클래스 자체가 템플릿이라면 명시적인 전문화가 아닌 부분적인 전문화가됩니다. 템플릿 기능의 일부 특수화는 허용되지 않습니다. 오버로드를 추가하는 std::swap
것이 대안이지만 명시 적으로 금지되어 있습니다 ( std
네임 스페이스 에 항목을 추가 할 수 없음 ). 따라서 ADL이 유일한 방법입니다 std::swap
.
std::swap()
는 약간 거꾸로 보입니다. std::swap()
유형에 특정한 과부하가 아닌를 선택 하면 문제가 발생할 것으로 예상합니다 A::swap()
. 의 예 std::swap(A::MyClass&, A::MyClass&)
는 오해의 소지가 있습니다. 이후 std
사용자 유형에 대한 특정 과부하를하지 않을 것, 나는 그것이 좋은 예라고 생각하지 않습니다.
MyNamespace::doSomething
뿐만 아니라 찾고 있기 때문에 실제로 작동했음을 증명합니다 ::doSomething
.
Koenig Lookup에서 네임 스페이스를 지정하지 않고 함수를 호출하면 함수의 이름 도 인수의 유형이 정의 된 네임 스페이스에서 검색됩니다. 그것은 또한으로 알려져 있습니다 이유입니다 인수 종속 이름 조회 짧은 단지로, ADL .
Koenig 조회로 인해 다음과 같이 작성할 수 있습니다.
std::cout << "Hello World!" << "\n";
그렇지 않으면 다음과 같이 작성해야합니다.
std::operator<<(std::operator<<(std::cout, "Hello World!"), "\n");
실제로 너무 많이 입력하고 코드가 정말 못 생겼습니다!
다시 말해 Koenig Lookup이 없으면 Hello World 프로그램 조차 복잡해 보입니다.
std::cout
ADL을 활성화하기에 충분한 함수에 대한 하나의 인수입니다. 그거 알아?
ostream<<
. 2) 정규화 된 이름 (예 : std::vector
또는 std::operator<<
). 3) Argument Dependent Lookup에 대한보다 자세한 연구.
std::endl
인수로 취할 수있는 함수 는 실제로 멤버 함수입니다. 어쨌든, "\n"
대신에 사용하면 std::endl
내 대답이 정확합니다. 의견 주셔서 감사합니다.
f(a,b)
호출은 무료 함수 를 호출하기 때문 입니다. 따라서의 경우 두 번째 인수로 사용 std::operator<<(std::cout, std::endl);
되는 무료 기능이 없습니다 std::endl
. std::endl
인수로 사용하고 작성해야하는 멤버 함수입니다 std::cout.operator<<(std::endl);
. 그리고 두 번째 인수로 사용 되는 자유 함수 가 있기 때문에 작동합니다. 잘 작동합니다. char const*
"\n"
'\n'
어쩌면 그 이유부터 시작하는 것이 가장 좋을 것입니다.
네임 스페이스가 도입되었을 때, 별도의 라이브러리가 서로 간섭하지 않도록 네임 스페이스에 모든 것을 정의하는 것이 아이디어였습니다. 그러나 이것은 운영자에게 문제를 일으켰습니다. 예를 들어 다음 코드를보십시오.
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()
내 의견으로는 그것에 관한 모든 것이 좋지는 않습니다. 컴파일러 공급 업체를 포함한 사람들은 때때로 불행한 행동으로 인해이를 모욕하고 있습니다.
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
.
std::begin
네임 스페이스 모호성을 지 웁니다.