Proper implementation in terms of implicit RValue conversion

I ran into a problem that RValue does not allow implicit conversion. My questions are that it is better to implement a “circumvention” of this limitation?

Here is a sample code to illustrate the problem:

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 in which RValue can be used, but the function wants a base, and the parameter is a derived failure.

Option 1

Option 1 to fix the problem:

 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 pass derivatives to the database before calling the function. This partially violates the goal, because a call requires the caller to find out the actual base type for the conversion (it is also the specific base type of the template template).

Option 2

Option 2 to fix the problem: (change the template and CallFunction function)

 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 do not know the restrictions that are currently imposed with RValue, but I'm not sure if there are enough typechecking static_asserts that eliminate the confusion if someone passes the wrong parameter.

Questions

  • Do you see something wrong with Option 2 or is Option 1 still the best route?

  • Is using SFINAE a way to clean type security?

+4
source share
1 answer

Well, this has nothing to do with rvalues, but rather the failure of template output.

Matching template parameters is very straightforward, as is simple pattern matching.

The following is one way to fix it using typedef in the interface class:

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

Cheers and hth.,

+2
source

Source: https://habr.com/ru/post/1337508/


All Articles