2010-12-06 9 views
4

다음 코드를 인쇄 :혼합 템플릿 함수 오버로드 및 상속

generic 
overload 

하지만 내가 원하는 것은 과부하 또는 전문성이없는 일반 하나, 두 경우 모두에서 호출 된 것입니다. 나는 오버로드를 템플릿 전문화와 섞어 쓰려고하지 않고 있으며, 내가 기대했던대로 아무도 일하지 않기 때문에 함께 존재합니다. 이 작업을 수행하기위한 템플릿 마법이 있습니까? 전문 기능을 사용하기 위해서는

#include <iostream> 

class Interface {}; 
class Impl: public Interface {}; 

class Bar 
{ 
public: 
    template<typename T> void foo(T& t) { 
     std::cout << "generic\n"; 
    } 
    void foo(Interface& t) { 
     std::cout << "overload\n"; 
    } 
}; 
template<> void Bar::foo<Interface>(Interface& t) { 
    std::cout << "specialization\n"; 
} 

int main() { 
    Bar bar; 
    Impl impl; 
    Interface& interface = impl; 
    bar.foo(impl); 
    bar.foo(interface); 
    return 0; 
} 

답변

5

두 가지 방법으로 type_traits을 사용하여 인수가 인터페이스에서 파생되었는지 테스트합니다.

#include <boost/type_traits.hpp> 

class Interface {}; 
class Impl: public Interface {}; 

class Bar 
{ 
    template <class T> void foo_impl(T& value, boost::false_type) 
    { 
     std::cout << "generic\n"; 
    } 
    void foo_impl(Interface& value, boost::true_type) 
    { 
     std::cout << "Interface\n"; 
    } 
public: 
    template<typename T> void foo(T& t) { 
     foo_impl(t, boost::is_base_of<Interface, T>()); 
    } 

}; 

조건이 충족되면 템플릿을 사용 중지하거나 템플릿 이외의 템플릿 만 후보로 남겨 둡니다.

#include <boost/utility/enable_if.hpp> 
#include <boost/type_traits.hpp> 

class Interface {}; 
class Impl: public Interface {}; 

class Bar 
{ 
public: 
    template<typename T> 
    typename boost::disable_if<boost::is_base_of<Interface, T>, void>::type foo(T& t) 
    { 
     std::cout << "generic\n"; 
    } 

    void foo(Interface&) 
    { 
     std::cout << "Interface\n"; 
    } 
}; 
2

는, 컴파일러는 &Impl에서 &Interface에 매개 변수의 변환을 수행해야합니다. 함수 시그너처 일치를 찾으면 정확히 일치하는 것이 변환이 필요한 것보다 우선합니다. 일반 foo<T>은 정확히 일치하므로 과부하 및 특수 기능 모두에서 우선합니다.

0

템플릿 정의 함수를 만들 수 있습니다 : Interface& 매개 변수를 사용하면 정의 된 것보다 더 나은 일치

void Bar::foo<Impl>(Impl& t) 

합니다.

당신은 아마도 다음과 같이 슈퍼 클래스 기능에게 더 나은 경기를 할 필요가 :

class Bar 
{ 
    struct fallback { fallback(int) {} }; 
    template<typename T> void foo(T& t, fallback) { 
     std::cout << "generic\n"; 
    } 
    void foo(Interface& t, int) { 
     std::cout << "overload\n"; 
    } 
public: 
    template<typename T> void foo(T& t) { 
     foo(t, 0); 
    } 
}; 

그래서 당신은 내부 형식 시험을 필요 했어 실제로 http://ideone.com/IpBAv

를 참조하지만 작동하지 않습니다 서브 클래스가 Interface 인 일반적인 버전.

+0

내가 처음에 코드를 살펴본 결과, GCC가 잘못 형성되었다고 생각하는 것과 동일한 이유로 잘못된 코드라고 생각했습니다. 그러나 두 번째 생각에, 템플릿 템플릿이 아닌 함수가 함수 템플릿 전문화보다 더 잘 일치하기 때문에이 템플릿이 비 템플릿으로 처리되어야한다고 생각합니다. –

+0

@Johannes : 솔루션을 알고 있습니까? –

+0

아니요, 위의 의견을 무시하십시오. "다른 모든 것이 동등한 경우"비 템플릿이 해당 매개 변수에 대해 더 나쁜 변환을 가지지 않고 해당 템플릿의 모든 매개 변수에 대해 더 좋은 변환이없는 경우 ". 그래서 저의 첫 코멘트가 말했듯이, 이것은 십자가입니다 : http://stackoverflow.com/questions/3519282/why-is-this-ambiguity-here/3525172#3525172, 그리고 GCC는 정확합니다. –