2017-01-13 15 views
6

:방지 암시 적 템플릿 인스턴스화과 같은 방법 과부하 상황에서

struct A 
{ 
    void foo(int i) { /*...*/ } 
    template<typename T> void foo(T t) { /*...*/ } 
} 

이 어떻게 명시 적으로 명령하지 않는 한 템플릿 인스턴스화를 방지 할 수 있습니다?

A a; 
a.foo<int>(1); // ok 
a.foo<double>(1.0); // ok 
a.foo(1); // calls non-templated method 
a.foo(1.0); // error 

감사합니다!

+3

이것이 필요합니까? 함수를 오버로딩하는 대신'int'에 대한 템플릿을 전문화하지 않는 이유는 무엇입니까? –

+0

@ChristianHackl 그냥'foo (double) = delete'을해라. 내 대답을 보라. – TemplateRex

답변

9

template argument deduction을 방지하는 depedent_type 구조체를 도입 할 수 있습니다. 귀하의 예제에서

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

struct A 
{ 
    void foo(int i) { /*...*/ }; 
    template<typename T> void foo(typename dependent_type<T>::type t) { /*...*/ } 
} 

: (.이 동작은 cppreference >template argument deduction >non-deduced contexts에 설명)

a.foo<int>(1);  // calls the template 
a.foo<double>(1.0); // calls the template 
a.foo(1);   // calls non-templated method 
a.foo(1.0);   // calls non-templated method (implicit conversion) 

wandbox example


당신이 a.foo(1.0) 제왕을 확인하려면

template <typename T> 
auto foo(T) -> std::enable_if_t<std::is_same<T, int>{}> { } 

이 기술은 foo의 위의 과부하는 int 인수 걸릴 수 있습니다 : ompilation 오류가, 첫 번째 과부하 제한 할 필요가 암시 적 변환 를 (예를 들어, float ~ int)은 허용되지 않습니다. 이것이 당신이 원하는 것이 아니라면, TemplateRex의 대답을 고려하십시오.

wandbox example

(a.foo<int>(1)를 호출 할 때 내가 안내 기본 규칙을 잘 모르겠어요으로 위의 제한된 기능으로, 두 개의 오버로드를 사이에 호기심 상호 작용이 나는. asked a question about it있다.)

지금까지 당신이 당신이 원하지 않는 명시 적으로 과부하를 삭제하는 것입니다 원하는 것을 할 수있는 간단한 방법으로
+0

은'foo (double) = delete'을 사용하면 훨씬 간단 해지며, enable_if와 non-deduced wrapper는 필요 없습니다. 내 anwer를보세요 : – TemplateRex

+0

이것은 나를위한 최선의 선택 인 것 같습니다. 컴파일러 컴플라이언스 요구 사항이 적 으면서'a.foo (1.0)'을 막는 또 다른 방법은'static_assert (std :: is_same , "...");'와 같은 것을하는 것입니다. – cyberguijarro

1

:

void foo(double) = delete; 

this prints

void A::foo(T) [with T = int] 
void A::foo(T) [with T = double] 
void A::foo(int) 

this prints

prog.cc: In function 'int main()': 
prog.cc:18:16: error: use of deleted function 'void A::foo(double)' 
    a.foo(1.0);   // error 
       ^
prog.cc:6:10: note: declared here 
    void foo(double) = delete; 
에 남아있는 마지막 줄에 주석 메인의 마지막 행으로

#include <iostream> 

struct A 
{ 
    void foo(int) { std::cout << __PRETTY_FUNCTION__ << "\n"; } 
    void foo(double) = delete; 

    template<typename T> 
    void foo(T) {std::cout << __PRETTY_FUNCTION__ << "\n"; } 
}; 

int main() 
{  
    A a; 
    a.foo<int>(1);  // ok 
    a.foo<double>(1.0); // ok 
    a.foo(1);    // calls non-templated method 
    a.foo(1.0);   // error  
} 

다음 명시 적으로 예를하기

+0

이 접근법은'float','char' * (그리고 암시 적으로'int'로 변환 가능한 모든 타입) *으로'foo'를 호출 할 수 있음에 유의하십시오. 이것이 OP가 원하는 것인지 확실하지 않습니다. –

+0

@VittorioRomeo 확실하지만 솔루션에도 똑같이 적용됩니다. 정확하게 'int'또는 부동 소수점 형 변환 또는 좁은 변환 만 원하는가? 어떤 경우에도'= delete' 솔루션은 다음과 같이 확장 될 수 있습니다. 다른 과부하를 제외 시키십시오 (오류가 있기 때문에 제거하지 마십시오). – TemplateRex

+0

네, 저는 당신의 대답을 비난하지 않고 있습니다 - 단지 당신이 그것을 언급해야한다고 말하고 있습니다. 내 대답을 업데이트하여 암시 적 변환이 허용되지 않음을 분명히합니다. –

0

냄비에 또 다른 제안을 추가하고, 비토리오의 답변으로 비슷한 맥락에서 당신은 또한 서명에 다른 템플릿 매개 변수를 추가 할 수 있습니다

다음
template <class UserType, class InputType> 
void foo(InputType x){...} 

이 될 수 없기 때문에 첫 번째 템플릿 매개 변수를 지정해야합니다 그것을 사용하는 추론했다. 이것은 사용자가 원했던 것과 전달 된 것을 구별 할 수있는 약간의 이점을 가지고 있습니다. 어떤 경우에는 사용할 수 있습니다.