2013-03-28 3 views
6

기본 클래스와 파생 클래스에 공유 포인터를 사용하는 오버로드 된 함수를 만들고 싶습니다. 참조 및 원시 포인터에서는 작동하지만 여분의 파생 클래스에서는 공유 포인터가 작동하지 않는 것 같습니다. 비주얼 스튜디오 2012를 사용하는 경우,하지만 난 여기 http://ideone.com/6uoa0p에 코드를하려고 할 때이 같은 결과를 얻을 내가 할공유 포인터로 인수 오버플로 함수 오버로드

#include <memory> 

class Base{}; 
class Derived : public Base {}; 
class ExtraDerived : public Derived {}; 


bool IsBase(Base*){ return true; } 
bool IsBase(Derived*){ return false; } 

bool IsBase(std::shared_ptr<Base>){ return true; } 
bool IsBase(std::shared_ptr<Derived>){ return false; } 

int main() 
{ 
    auto derived = std::make_shared<Derived>(); 
    auto extra_derived = std::make_shared<ExtraDerived>(); 
    // works 
    auto raw_result_derived = IsBase(derived.get()); 
    auto raw_result_extra_derived = IsBase(extra_derived.get()); 
    auto shared_result_derived = IsBase(derived); 
    // doesn't work 
    auto shared_result_extra_derived = IsBase(extra_derived); 
} 

: "오버로드 된 함수에 대한 모호한 호출 오류 C2668 : 'IsBase' '예제 코드를 참조하십시오 .

이것은 '원시'물건에 대해 작동하므로 원하는 동작처럼 보이지 않습니다. 이것이 templating의 한계입니까, 이것이 작동하지 않거나 버그가되는 또 다른 이유가 있습니까? 그리고 어떻게하면 가장 못생긴 방식으로 작동하게 할 수 있습니까?

내가 가지고 올 수있는 가장

//ugly workaround 
bool IsBase(std::shared_ptr<Base>, Base*){ return true; } 
bool IsBase(std::shared_ptr<Derived>, Derived*){ return false; } 
template<typename T> bool IsBase(std::shared_ptr<T> input) 
{ 
    return IsBase(input, input.get()); 
} 
+4

을 당신이 원하는 이유는 무엇입니까? 그냥 기본 함수를 제공합니다, 그것은 행복하게 파생 클래스 포인터를 받아 들일 것입니다. 파생 클래스 객체를 catch하려면 함수의 동적 유형에 대한 디스패치가 필요하므로 메서드가 제대로 작동하지 않습니다. 프로그래머가'Ptr '을'Ptr '으로 암시 적으로 변환하면이 오버로드 접근법이 무너집니다. –

+0

@ JohannesSchaub-litb 나는 그 상황을 생각하지 않았다. 나는 내가 원하는 것을 다시 생각해야 할 수도 있습니다. – Barabas

답변

4

이 템플릿의 제한이 있습니다, 문제가 해결되지 않거나이 버그가 또 다른 이유가있다?

아니요, 이것은 버그가 아닙니다. 실제로 똑똑한 포인터의 유일한 함정에 부딪 혔습니다 : 은 std::shared_ptr<derived>std::shared_ptr<extra_derived>에서 구성 될 수 있지만이 두 변환 시퀀스 중 어느 것도 다른 것보다 우수하지 않습니다 (두 개의 사용자 정의 변환 시퀀스가 ​​동일합니다 길이).

그러나 여전히 일부 SFINAE 제약 조건을 사용하여 과부하를 해결할 수 :

#include <type_traits> 

// Selected for `std::shared_ptr<Base>` 
template<typename T, typename std::enable_if< 
    std::is_same<T, Base>::value>::type* = nullptr> 
bool IsBase(std::shared_ptr<T>){ return true; } 

// Selected for `std::shared_ptr<T>` where T is a class derived from Base, 
// but not Base itself 
template<typename T, typename std::enable_if< 
    std::is_base_of<Base, T>::value && 
    !std::is_same<T, Base>::value 
    >::type* = nullptr> 
bool IsBase(std::shared_ptr<T>){ return false; } 
+0

슬프게도 이것은 VS2012에서는 작동하지 않지만 앞으로는 작동해야합니다. 이 간단한 경우에는 작동하지만 파생 클래스마다 오버로드가 많으면 문제가 될 수 있습니다. 필자는 실제로 이런 기능을 원할지, 아니면 질문에 JohannesSchaub-litb의 의견을 고려하지 않을지에 대해 생각해야 할 것입니다. – Barabas