Начиная с C ++ 17, теперь намного проще создать экземпляр класса, который имеет множество параметров шаблона, которые могут быть автоматически выведены из вызова конструктора.

В моем проекте у меня есть иерархия шаблонных классов, которые могут быть вложены один в другой, что приводит к огромным именам типов, что является причиной того, почему вывод аргументов шаблона класса так хорош.

Однако я использую также статические фабричные методы, чтобы упростить динамическое построение классов (в основном я просто возвращаю shared_ptrs, содержащий вновь созданный объект). Как в примере ниже

#include <iostream>
#include <memory>

template <typename T>
struct S {
    const std::shared_ptr<T> m_t;
    S(std::shared_ptr<T> t):
        m_t {std::move(t)} {}

    template<typename ...Args>
    static S create(Args&&... args);
};

template <typename T>
template <typename ...Args>
std::shared_ptr<S<T>> S<T>::create(Args&&... args) {
    return std::make_shared<S<T>>(std::forward<Args>(args)...);
}




int main() {
    auto s1 = S{std::make_shared<int>(6)};
    // auto s2 = S::create(std::make_shared<int>(5));   // DOESN'T work
}

Мне нужны указатели для включения полиморфизма (если нет другого способа, который не требует указателей - может быть, CRTP), но я не вижу способа упростить процесс создания экземпляра без необходимости где-то указывать полный тип возвращаемого объекта.

0
A.Budziak 24 Ноя 2018 в 23:05

1 ответ

Лучший ответ
template <typename ...Args>
auto createS(Args&&... args) {
    return std::make_shared<decltype(S{std::forward<Args>(args)...})>(std::forward<Args>(args)...);
}

int main() {
    auto s1 = S{std::make_shared<int>(6)};
    auto s2 = createS(std::make_shared<int>(5));
}

Это должно гарантировать, что тип выводится точно так же, как для s1.

Фактически, вы можете обобщить это для вывода любого аргумента шаблона класса:

template <template<typename...> class Tmpl, typename ...Args>
auto make_shared_deduced(Args&&... args) {
    return std::make_shared<decltype(Tmpl{std::forward<Args>(args)...})>(std::forward<Args>(args)...);
}

int main() {
    auto s1 = S{std::make_shared<int>(6)};
    auto s2 = make_shared_deduced<S>(std::make_shared<int>(5));
}

См. Также стандартное предложение P1069R0.

Я не знаю, действительно ли тебе нужно все это shared_ptr. Вероятно, их следует использовать только в очень определенных случаях, а не в большинстве случаев.

3
25 Ноя 2018 в 01:20