ADL이 함수 템플릿을 찾지 못하는 이유는 무엇입니까?


85

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.
}

ns :: frob ()을 작성하지 않고 frob () 작업을 기대한다는 뜻입니까?
Simon

예, 비 템플릿 기능 방식입니다.
Hugh

참고로 Comeau에서도 위의 코드가 실패합니다 : comeaucomputing.com/tryitout- 추가 using namespace ns;또는 ns::검증이 컴파일을 통과합니다. 이것은 좋은 질문입니다.
fbrereto 2010-06-01

3
@Huw : 내가 생각에서 그냥 물린 :) 재미는 방법을 명시 적 자격 ADL 규칙 : /
마티유 M.

1
@Matt : 하하, 그리고 나도 방금. 작은 프로그래밍 세계.
GManNickG 2011 년

답변:


88

이 부분에서 설명합니다.

C ++ 표준 03 14.8.1.6 :

[참고 : 간단한 함수 이름의 경우 함수 이름이 호출 범위 내에 표시되지 않는 경우에도 인수 종속 조회 (3.4.2)가 적용됩니다. 이는 호출이 여전히 함수 호출 (3.4.1)의 구문 형식을 가지고 있기 때문입니다. 그러나 명시 적 템플릿 인수가있는 함수 템플릿을 사용하는 경우 호출 지점에 해당 이름을 가진 함수 템플릿이 없으면 호출에 올바른 구문 형식이 없습니다. 이러한 이름이 표시되지 않으면 호출이 구문 상 제대로 구성되지 않은 것이며 인수 종속 조회가 적용되지 않습니다. 이러한 이름이 표시되면 인수 종속 조회가 적용되고 다른 네임 스페이스에서 추가 함수 템플릿을 찾을 수 있습니다.

namespace A {
  struct B { };
  template<int X> void f(B);
}
namespace C {
  template<class T> void f(T t);
}
void g(A::B b) {
  f<3>(b);    //ill-formed: not a function call
  A::f<3>(b); //well-formed
  C::f<3>(b); //ill-formed; argument dependent lookup
              // applies only to unqualified names
  using C::f;
  f<3>(b);    //well-formed because C::f is visible; then
              // A::f is found by argument dependent lookup
}

9
이것에 대한 근거는 무엇입니까? 이상한 요구 사항처럼 보입니다. 내 말은, 통 사적 형태는 어떤 것과 관련이 있습니까?
궤도의 가벼운 경주

22
이 이유 Vandevoorde & Josuttis에의 @LightnessRacesinOrbit 제 9.3.5 설명 이다 "것을 결정할 수없는 컴파일러 : (OP의 예에 채택 된 네이밍)는 구문 문제 f<3>(b)가 결정 될 때까지 함수 호출 인수입니다 <3>템플릿 인수 목록입니다 반대로, 우리가. <3>우리가 템플릿 이라는 것을 알기 전까지는 그것이 템플릿 인수 목록 인지 결정할 수 없습니다 f().이 닭과 달걀 문제는 해결할 수 없기 때문에 표현식은으로 구문 분석됩니다 (f<3)>(b). template이는 멤버 함수 템플릿 의 명확성 구문 과 유사합니다 .
TemplateRex

9
이 문제를 해결하기위한 제안이 있습니까? template f<3>(b)더 나은 구문이 될 수 있습니까?
balki 2015-06-05

1
@AngelusMortis 표현식 ( 표현식 ... ) (괄호 앞에 연산자가 없음)은 항상 함수 호출이며 컴파일러는 여는 괄호를 보는 즉시이를 인식합니다. 여기서 문제 <는 연산자와 템플릿 인수 목록의 시작 역할을 모두 수행 할 수 있으며 컴파일러는 어떤 것을 파악하기 위해 많은 추가 구문 분석을 수행해야한다는 것입니다. 모호하지 않게). 표준 작성자는 컴파일러 개발자의 머리를 구하기 위해 불법으로 만들기로 선택한 것으로 보입니다.
Miral

3
이 요구 사항은 C ++ 20에서 해제되었으며 OP의 코드는 이제 잘 구성되었습니다. :)
Rakete1111

8

C ++ 20부터 adl은 명시 적 함수 템플릿에서도 잘 작동합니다. 제안은 다음과 같습니다. P0846R0 : 보이지 않는 ADL 및 기능 템플릿 :

사용자에게 템플릿 키워드를 사용하도록 요구하는 대신, 일반 조회가 결과를 생성하지 않거나 하나 이상의 함수를 찾고 뒤에 "<"가 오는 이름이 다음과 같이 처리되도록 조회 규칙에 대한 개정이 제안되었습니다. 기능 템플릿 이름이 발견되어 ADL이 수행되는 경우

현재 GCC 9 만이 기능을 구현하므로 예제를 컴파일 할 수 있습니다.

live demo.


5

약간 받아 들여진 답변을 수정하고 싶습니다. OP 질문에서는 명확하지 않지만 표준 (Kornel에서 인용)에서 중요한 부분은 다음과 같습니다 (강조 내) :

그러나 명시 적 템플릿 인수가 있는 함수 템플릿을 사용하면 호출에 올바른 구문 형식이 없습니다.

따라서 금지 된 것은 ADL에 의존하고 명시적인 템플릿 인수를 사용하는 것입니다. 불행히도 비 유형 템플릿 인수를 사용하려면 명시 적 인수를 사용해야합니다 (기본값이없는 경우).

다음은이를 보여주는 샘플 코드입니다. :

[라이브]

#include <string>
#include <utility>

namespace C {
  struct B { };
  template<class T> void f(T t){}
}

void g(C::B b) {
  f(b);           // OK
  //f<C::B>(b);   // ill-formed: not a function call, but only 
                  //  because explicit template argument were used

  std::string s;
  move(s);                      // OK
  //move<std::string&>(s);      // Error, again because 
                                //  explicit template argument were used
  std::move<std::string&>(s);   // Ok
}

int main()
{
 C::B b;
 g(b);
}

0

편집 : 아니, 이것은 옳지 않습니다. @Kornel의 답변을 참조하십시오 .


확실하지는 않지만 Stroustrup의 "The C ++ programming language"를 참조하여 부록 C 섹션 13.8.4 원인 있다고 생각합니다 .

frob은 템플릿 이므로 i=0호출 한 후 특정 시점에 이를 전문화 할 수 있습니다. 즉 frob, 인스턴스화 지점 이나 번역 단위 처리가 끝날 때 선택할 수있는 것처럼 보이는대로 호출 할 항목 을 선택하는 두 가지 가능한 방법이 구현에 남게됩니다 .

그래서 문제는 당신이 할 수 있다고 생각합니다

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

int main() {
    ns::foo f;
    frob<0>(f);
    return 0;
}

namespace ns {
    template<> void frob< 0 >(foo const&) { /* Do something different*/ }
}

1
아니요, 네임 스페이스를 가져와도 여전히 문제가 있습니다. 그렇죠? 사용 후 전문화는 C ++에서 일반적인 문제이며 이후에 선언 된 경우 특수화 된 형식이 사용되지 않습니다.
Kornel Kisielewicz 2010-06-01

@Kornel : 아 예, 다른 오류가 발생합니다. 제가 설명한 내용과 일치합니다. 충분합니다. 지적 해 주셔서 감사합니다.
Troubadour
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.