2012-12-20 2 views
12

최소 프로그램 :동일한 서명으로 템플릿 함수에 오버로드가 발생하는 이유는 무엇입니까?

#include <stdio.h> 

#include <type_traits> 

template<typename S, typename T> 
int foo(typename T::type s) { 
    return 1; 
} 

template<typename S, typename T> 
int foo(S s) { 
    return 2; 
} 

int main(int argc, char* argv[]) { 
    int x = 3; 
    printf("%d\n", foo<int, std::enable_if<true, int>>(x)); 

    return 0; 
} 

출력 :

1 

왜이 컴파일 에러를 제공하지 않습니다? 템플릿 코드가 생성되면 int foo(typename T::type search)int foo(S& search) 함수의 서명이 같지 않습니까? 템플릿 기능이 조금, 여전히 (내가 위의 예 주어진 기대하는 것처럼) 작동 시그니처 변경하는 경우

: 아직

template<typename S, typename T> 
void foo(typename T::type s) { 
    printf("a\n"); 
} 

template<typename S, typename T> 
void foo(S s) { 
    printf("b\n"); 
} 

를이 없습니다 아직 유일한 차이점은 하나는 가지고 있다는 것입니다 않습니다 int 시그니처와 다른 것은 최초의 템플릿 파라미터로 정의됩니다.

template<typename S, typename T> 
void foo(typename T::type s) { 
    printf("a\n"); 
} 

template<typename S, typename T> 
void foo(int s) { 
    printf("b\n"); 
} 

컴파일러 오류 (연타) :

test.cpp:26:2: error: call to 'foo' is ambiguous 
foo<std::enable_if<true, int>>(3); 
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
test.cpp:16:6: note: candidate function [with T = std::__1::enable_if<true, int>] 
void foo(typename T::type s) { 
     ^
test.cpp:21:6: note: candidate function [with T = std::__1::enable_if<true, int>] 
void foo(int s) { 
     ^
1 error generated. 
내가 일하고 있어요 프로젝트에 대한이 유사한 코드를 사용하고

내가 미묘 언어에가 있다는 것을 두려워하는 I 어떤 경우에는 정의되지 않은 행동을 일으키는 것을 이해하지 못합니다. 또한 Clang과 VS11에서 모두 컴파일되므로 컴파일러 버그라고 생각하지 않습니다.


편집 : 수정 된 두 번째 경우 (오타); Clang에서 오류 메시지를 추가했습니다.

편집 # 2 : T :: type의 의미를 묻는 질문에 대한 답변입니다. http://en.cppreference.com/w/cpp/types/enable_if 가입일

:

템플릿 < 부울 B 클래스 T = 무효> 구조체 enable_if;

B가 참인 경우 std :: enable_if는 public member typedef 유형을가집니다. to T; 그렇지 않으면 typedef 멤버가 없습니다.

enable_if는 구조체입니다. 기본적으로 enable_if의 첫 번째 템플릿 매개 변수에서 평가 된 표현식이 참이면 (위 예제의 경우), 두 번째 템플릿 매개 변수와 동일한 유형을 갖는 public 멤버 type이 있습니다.

enable_if<true, int>의 경우 enable_if :: type의 유형은 int입니다.

+1

마지막 사례가 컴파일되지 않는 것은 놀라운 일이 아닙니다. 함수가 하나만 받으면 두 개의 템플릿 인수를 사용합니다. –

+0

고마워, 거기에 잘못된 경우를 복사 한 것 같아. 결정된. – vmrob

+0

저는 C++ 멍청한 녀석입니다. 가혹하지 않습니다 ... 첫 번째 예제를 재정의했기 때문에 첫 번째 예제가 작동하지 않습니까? 나는 이것에 대한 답을 알고 싶다. 내년에 C++을 배울 계획입니다. –

답변

7

첫 번째 기능은 첫 번째 기능보다 전문화 된 것으로 간주됩니다.

함수

int foo(typename T::type) 

파라미터 S의 값으로 T :: 형식을 사용하여

template <typename S,typename T> int foo(S s) 

일치 할 수 있지만

int foo(S s) 

template <typename S,typename T> int foo(typename T::type) 
일치하지 않을

T를 추론 할 수 없으므로

로직은 14.5.5.2 절의 C++ 03 표준과 14.5.6.2 절의 C++ 11 표준에 레이아웃되어 있습니다.

하나의 함수가 다른 함수보다 더 특수화되어 있는지 확인하려면 첫 번째 함수의 각 템플릿 매개 변수에 대한 값을 생성 한 다음 두 번째 함수가 결과 서명과 일치하는지 확인합니다. 또한 두 번째 함수의 템플릿 매개 변수에 대한 값을 만들고 첫 번째 함수가 결과 서명과 일치하는지 확인합니다. 두 번째 기능이 첫 번째 기능과 일치 할 수 있다면 두 번째 기능은 첫 번째 기능보다 더 전문화 될 수 없습니다. 그 외에도 첫 번째 기능이 두 번째 기능과 일치 할 수없는 경우 첫 번째 기능은 두 번째 기능보다 더 전문화되어야합니다. 그것은 당신이 가진 경우입니다.

2

여기 현상의 더욱 단순화입니다 :

#include <stdio.h> 

template<typename T> 
void foo(int arg) { 
    printf("a\n"); 
} 

template<typename T> 
void foo(T arg) { 
    printf("b\n"); 
} 

int main(int argc, char* argv[]) { 
    foo<int>(3); // prints "a" 
    foo(3);  // prints "b" 

    return 0; 
} 

템플릿 매개 변수 중 하나를 명시 적으로 꺾쇠 괄호를 통해 전달 될 수도 있고 공제를 통해 해결할 수 있습니다. 매개 변수가 명시 적으로 지정되지 않은 경우 함수의 인수를 사용하여 공제 할 수 있어야합니다.

foo(3)의 경우 매개 변수 T가 명시 적으로 지정되지 않고 추론 할 수 없기 때문에 'a'템플릿이 작동하지 않습니다. foo<int>(3)의 경우 두 템플릿 모두 작동 할 수 있습니다. 실제로 템플릿 'a'를 주석 처리하면 foo<int>(3)을 호출하면 "b"가 인쇄됩니다. 그래서 질문은 '템플릿'이 선호되는 이유는 무엇입니까? 열쇠는 여기에 "부분적인 순서"입니다 :

나는 다른 사람이 이미 응답 한 것을 지금 볼 http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fpartial_ordering_funct_templ.htm

(나는 신속하게 질문에 대답에 나쁜 해요), 그래서 지금이 마무리거야 및 본이 말한 것처럼 템플리트 'a'가 더 전문화되어 있다고 말합니다.

관련 문제