我想制作重载函数,这些函数采用指向基类和派生类的共享指针。它似乎适用于引用和原始指针,但在额外派生类的情况下不适用于共享指针。查看示例代码:
#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);
}
我在使用 Visual Studio 2012 时得到:“错误 C2668:‘IsBase’:对重载函数的调用不明确”,但在此处尝试代码时我也得到相同的结果 http://ideone.com/6uoa0p .
这看起来不像是期望的行为(因为它适用于“原始”内容)。这是模板的限制吗,还有其他原因导致它不起作用或者它是一个错误吗? 我怎样才能让它以最不丑陋的方式工作?
我能想到的最好的是
//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());
}
最佳答案
Is this a limitation of the templating, is there another reason why this doesn't work or is it a bug?
不,这不是错误。事实上,您似乎遇到了智能指针的唯一陷阱:std::shared_ptr<base>
。可以从 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; }
关于c++ - 具有共享指针参数歧义的函数重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15691726/