Аналогичное решение @evoskuil, которое сокращает шаблон в производных классах, если вы захотите реализовать функцию shared_from_this()
, в результате чего в точке использования в классе будет приведен следующий код:
auto shared_from_this() {
return shared_from(this);
}
При этом используются функции «shim» вне класса. Делая это таким образом, он также обеспечивает чистый способ сделать это для классов, интерфейс которых не может быть изменен, а является производным от enable_shared_from_this
- например,
auto shared_that = shared_from(that);
Примечание: использование auto
для типов возврата здесь будет зависеть от возраста вашего компилятора.
Функции Shim, которые можно поместить в заголовок библиотеки:
template <typename Base>
inline std::shared_ptr<Base>
shared_from_base(std::enable_shared_from_this<Base>* base)
{
return base->shared_from_this();
}
template <typename Base>
inline std::shared_ptr<const Base>
shared_from_base(std::enable_shared_from_this<Base> const* base)
{
return base->shared_from_this();
}
template <typename That>
inline std::shared_ptr<That>
shared_from(That* that)
{
return std::static_pointer_cast<That>(shared_from_base(that));
}
Приведенный выше код основан на том факте, что тип, переданный в shared_from(...)
, наследуется от std::enable_shared_from_this<Base>
в какой-то момент его происхождения.
Позвонив по номеру shared_from_base
, вы выясните, какой это был тип. Поскольку мы знаем, что That
наследуется от Base
, можно сделать статический уклон.
Возможно, есть некоторые патологические угловые случаи с классами, имеющими операторы преобразования типов ... но это вряд ли произойдет в коде, не предназначенном для этого.
Пример:
struct base : public std::enable_shared_from_this<base> {};
struct derived : public base
{
auto shared_from_this() {
return shared_from(this);
}
// Can also provide a version for const:
auto shared_from_this() const {
return shared_from(this);
}
// Note that it is also possible to use shared_from(...) from
// outside the class, e.g.
// auto sp = shared_from(that);
};
template <typename X>
struct derived_x : public derived
{
auto shared_from_this() {
return shared_from(this);
}
};
Тест на компиляцию:
int main()
{
auto pbase = std::make_shared<base>();
auto pderived = std::make_shared<derived>();
auto pderived_x = std::make_shared<derived_x<int> >();
auto const& const_pderived = *pderived;
const_pderived.shared_from_this();
std::shared_ptr<base> test1 = pbase->shared_from_this();
std::shared_ptr<derived> test2 = pderived->shared_from_this();
std::shared_ptr<derived_x<int> > test3 = pderived_x->shared_from_this();
return 0;
}
https://onlinegdb.com/SJWM5CYIG
Предыдущее решение , которое я опубликовал, сохранило, чтобы комментарии все еще имели смысл - это поместило функции в базовый класс, у которого были некоторые проблемы - особенно неравномерность между требуемой реализацией для «нормальных» классов и шаблоны классов.
Кроме того, реализация в базовом классе должна быть повторена для новых иерархий классов, что не является СУХОЙ.
Кроме того, функция базового класса страдала от возможности неправильного использования, предоставляя указатель базового класса из другого объекта. Более новая схема, описанная выше, полностью исключает это, и проверка assert (...) во время выполнения выполняется.
Старая реализация:
#include <cassert>
#include <memory>
class base : public std::enable_shared_from_this<base>
{
protected:
template <typename T>
std::shared_ptr<T> shared_from(T* derived) {
assert(this == derived);
return std::static_pointer_cast<T>(shared_from_this());
}
};
class derived : public base
{
public:
auto shared_from_this() {
return shared_from(this);
}
};
template <typename X>
class derived_x : public derived
{
public:
auto shared_from_this() {
return this->template shared_from(this);
}
};
int main()
{
auto pbase = std::make_shared<base>();
auto pderived = std::make_shared<derived>();
auto pderived_x = std::make_shared<derived_x<int> >();
std::shared_ptr<base> test1 = pbase->shared_from_this();
std::shared_ptr<derived> test2 = pderived->shared_from_this();
std::shared_ptr<derived_x<int> > test3 = pderived_x->shared_from_this();
return 0;
}