Я столкнулся с проблемой, что 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 есть способ очистить тип безопасности?