在没有 RValue 隐式转换的情况下正确实现
我遇到了 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 可以在有人传递错误参数时消除混乱。
问题
您认为选项 2 有什么问题吗?或者选项 1 仍然是更好的路线吗?
使用 SFINAE 有没有办法清理类型安全?
I ran into the problem that RValue does not allow implicit conversion. My questions is what implementation is better to "bypass" this limitation?
Here is example code to illustrate the issue:
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
All calls where RValue could be utilized but the function wants the base and the parameter is the derived fail.
Option 1
Option 1 to correct the issue:
CallFunction(std::static_pointer_cast< ITestClass<int> >(std::make_shared<CTestClass>()));
CallFunction(std::static_pointer_cast< ITestClass<int> >(ptrDerived));
This option requires the user to cast the derived into the base before calling the function. This defeats the purpose some because it requires the caller to know the actual base type for the conversion (aka what concrete template instantiation base type it is).
Option 2
Option 2 to correct the issue:
(modify the template and CallFunction some)
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
I like option 2 better because callers don't know the limitation that is currently imposed with RValue but I am not sure if there are enough typechecking static_asserts that would clear up the confusion if someone passes the wrong parameter.
Questions
Do you see anything wrong with Option 2 or is Option 1 still the better route?
Using SFINAE is there a way to clean the type safety?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
嗯,它与右值没有任何关系,而是与模板参数推导失败有关。
模板参数匹配非常非常直接,就像简单的模式匹配一样。
以下是解决该问题的一种方法,即在接口类中使用
typedef
:Cheers &呵呵,
Well, it doesn't have anything to do with rvalues, but rather with template parameter deduction failure.
Template parameter matching is very very direct, like a simple pattern matching.
The following is one way to resolve it, using a
typedef
in the interface class:Cheers & hth.,