我遇到了RValue不允许隐式转换的问题。我的问题是,哪种实现方案更好地“绕过”此限制?
这是示例代码说明问题:
template<typename myVal>
class ITestClass
{
public:
virtual void myFunc(myVal item) = 0;
virtual myVal myFunc1() = 0;
};
class CTestClass : public ITestClass<int>
{
public:
void myFunc(int item) { }
int myFunc1() { return 0; }
};
template <typename T>
inline int CallFunction(std::shared_ptr< ITestClass<T> > ptrBase)
{
return 0;
}
inline std::shared_ptr< ITestClass<int> > GetBase()
{
return std::make_shared<CTestClass>();
}
std::shared_ptr< ITestClass<int> > ptrBase = std::make_shared<CTestClass>();
std::shared_ptr< CTestClass > ptrDerived = std::make_shared<CTestClass>();
CallFunction(ptrBase); // WORKS
CallFunction(GetBase()); // WORKS
CallFunction(std::make_shared<CTestClass>()); // ERROR
CallFunction(ptrDerived); // ERROR
可以使用RValue但函数需要基数且参数为派生失败的所有调用。
选项1
解决方案1:
CallFunction(std::static_pointer_cast< ITestClass<int> >(std::make_shared<CTestClass>()));
CallFunction(std::static_pointer_cast< ITestClass<int> >(ptrDerived));
此选项要求用户在调用函数之前将派生对象转换为基本对象。这在某些方面达不到目的,因为它要求调用者知道转换的实际基本类型(又是具体的模板实例化基本类型)。
选项2
选项2更正此问题:
(修改模板和CallFunction一些)
template<typename myVal>
class ITestClass
{
public:
typedef myVal class_data_type;
virtual void myFunc(myVal item) = 0;
virtual myVal myFunc1() = 0;
};
class CTestClass : public ITestClass<int>
{
public:
void myFunc(int item) { }
int myFunc1() { return 0; }
};
template <typename T>
inline int CallFunction(std::shared_ptr<T> ptrBase)
{
static_assert(std::is_base_of<ITestClass<typename T::class_data_type>, T>::value, "Class needs to derive from ITestClass"); // some example of type checking
return 0;
}
CallFunction(std::make_shared<CTestClass>()); // now works as normal
CallFunction(ptrDerived); // now works as normal
我更喜欢选项2,因为调用者不知道RValue当前施加的限制,但是我不确定是否有足够的类型检查static_asserts来清除如果有人传递错误的参数会造成的困惑。
问题
最佳答案
好吧,它与右值无关,而是与模板参数推导失败有关。
模板参数匹配非常直接,就像简单的模式匹配一样。
以下是在接口(interface)类中使用typedef
来解决此问题的一种方法:
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
namespace our = boost;
template<typename myVal>
class ITestClass
{
public:
typedef myVal ValType;
virtual void myFunc(myVal item) = 0;
virtual myVal myFunc1() = 0;
};
class CTestClass : public ITestClass<int>
{
public:
void myFunc(int item) { }
int myFunc1() { return 0; }
};
template <typename T>
inline int CallFunctionAux(
our::shared_ptr< ITestClass<T> > ptrBase
)
{
return 0;
}
template< class T >
inline int CallFunction( our::shared_ptr< T > ptrBase )
{
return CallFunctionAux< typename T::ValType >( ptrBase );
}
inline our::shared_ptr< ITestClass<int> > GetBase()
{
return our::make_shared<CTestClass>();
}
int main()
{
our::shared_ptr< ITestClass<int> > ptrBase = our::make_shared<CTestClass>();
our::shared_ptr< CTestClass > ptrDerived = our::make_shared<CTestClass>();
CallFunction(ptrBase); // WORKS
CallFunction(GetBase()); // WORKS
CallFunction(our::make_shared<CTestClass>()); // WORKS
CallFunction(ptrDerived); // WORKS
}
干杯,……