简体   繁体   中英

Combing two factory methods returning unique_ptr and shared_ptr into one in C++?

Lets assume I have two factory functions, one returning std::unique_ptr and the other returning std::shared_ptr :

template<class T, class... Args>
std::shared_ptr<T> createObjectS (Args... args)
{
  // running some code
  return std::make_shared<T>(args...);
}
template<class T, class... Args>
std::unique_ptr<T> createObjectU (Args... args)
{
  // running some code
  return std::make_unique<T>(args...);
}

Is it possible to combine these two functions into one using template meta programming?

You could use SFINAE, but then I don't really see the point to have this inside a function anymore. It's pretty redundant.

#include <memory>
#include <type_traits>

template <class T, class... Args>
typename std::enable_if<
    std::is_same<T, std::shared_ptr<typename T::element_type>>::value, T>::type
createObject(Args&&... args) {
    // running some code
    return std::make_shared<typename T::element_type>(std::forward<Args>(args)...);
}
template <class T, class... Args>
typename std::enable_if<
    std::is_same<T, std::unique_ptr<typename T::element_type>>::value, T>::type
createObject(Args&&... args) {
    // running some code
    return std::make_unique<typename T::element_type>(std::forward<Args>(args)...);
}

int main() {
    auto s = createObject<std::shared_ptr<int>>(1);
    auto u = createObject<std::unique_ptr<int>>(1);
}

A little bit more compact but essentially the same idea with a scoped enum

#include <memory>

enum class ptr_t { shared, unique };

template <ptr_t P, class T, class... Args>
typename std::enable_if<P == ptr_t::shared, std::shared_ptr<T>>::type
createObject(Args&&... args) {
    // running some code
    return std::make_shared<T>(std::forward<Args>(args)...);
}
template <ptr_t P, class T, class... Args>
typename std::enable_if<P == ptr_t::unique, std::unique_ptr<T>>::type
createObject(Args&&... args) {
    // running some code
    return std::make_unique<T>(std::forward<Args>(args)...);
}

int main() {
    auto s = createObject<ptr_t::shared, int>(1);
    auto u = createObject<ptr_t::unique, int>(1);
}

In C++17 you of course use if constexpr in both cases rather than SFINAE.

#include <memory>

enum class ptr_t { shared, unique };

template <ptr_t P, class T, class... Args>
decltype(auto) createObject(Args &&... args) {
    // running some code
    if constexpr (P == ptr_t::shared) {
        return std::make_shared<T>(std::forward<Args>(args)...);
    } else if (P == ptr_t::unique) {
        return std::make_unique<T>(std::forward<Args>(args)...);
    }
}

With specialization, you may do:

template <typename T> struct FactoryImpl;

template <typename T> struct FactoryImpl<std::unique_ptr<T>>
{
    template <typename ... Ts>
    auto operator ()(Ts&&... args) const
    {
        return std::make_unique<T>(std::forward<Ts>(args)...);
    }
};

template <typename T> struct FactoryImpl<std::shared_ptr<T>>
{
    template <typename ... Ts>
    auto operator ()(Ts&&... args) const
    {
        return std::make_shared<T>(std::forward<Ts>(args)...);
    }
};

template<class T, class... Ts>
auto createObjectS (Ts&&... args)
{
    return FactoryImpl<T>{}(std::forward<Ts>(args)...);
}

with usage:

auto s = createObject<std::shared_ptr<MyObject>>(42);
auto u = createObject<std::unique_ptr<MyObject>>(42);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM