Function overload with uncertainty of shared pointer argument

I want to make overloaded functions that use a generic pointer to a base class and derived classes. This seems to work for references and raw pointers, but not for general pointers in the case of an additional derived class. See Code Example:

#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); } 

I get: "error C2668:" IsBase ": ambiguous call of the overloaded function" when using Visual Studio 2012, but I also get the same result when I try to use the code here http://ideone.com/6uoa0p .

This does not seem to be the desired behavior (since it works for raw material). Is this a limitation of patterns, is there another reason why this does not work or is it a mistake? And how can I make it work in the least ugly way?

The best I can come up with is

 //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()); } 
+6
source share
1 answer

Is this a limitation of patterns, is there another reason why this does not work or is it a mistake?

No, this is not a mistake. Indeed, it seems that you got into the only error of smart pointers: std::shared_ptr<base> can be built from std::shared_ptr<derived> , as well as from std::shared_ptr<extra_derived> , but none of these two sequences conversions are not better than others (being two user-defined, certain conversion sequences of the same length).

However, you can fix your overloads using some of the limitations of 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; } 
+4
source

All Articles