如何在堆上 make_from_tuple ?

Cas*_*Cow 18 c++ tuples variadic-templates

所以在 C++ 中,现在 make_from_tuple 为:

T obj = std::make_from_tuple<T>( { Args... args } ); // args represents a tuple
Run Code Online (Sandbox Code Playgroud)

但人们会怎么做:

T* obj = std::make_new_from_tuple<T*>( { Args... args } );
Run Code Online (Sandbox Code Playgroud)

有 make_shared 和 make_unique 但它们都不接受元组(而且我不确定如何从元组中提取参数,如果这是要走的方向,因为如果您想要原始指针,您总是可以 make_unique 然后释放) 。

非常简单的例子1:

struct A
{
    int i_; double d_; std::string s_;

    A( int i, double d, const std::string& s ) : i_(i), d_(d), s_(s) {}
};

auto aTuple = std::make_tuple( 1, 1.5, std::string("Hello") );
Run Code Online (Sandbox Code Playgroud)

对于更复杂的示例,如果元组包含要转发的 unique_ptr,我也希望它能够工作。

Ala*_*les 15

您基本上可以从 cppreference 的可能实现中复制实现,然后将其放入 a 中make_unique,它就可以工作了:

#include <string>
#include <memory>

namespace detail {
template<class T, class Tuple, std::size_t... I>
constexpr std::unique_ptr<T> make_new_from_tuple_impl(Tuple&& t, std::index_sequence<I...>)
{
    static_assert(std::is_constructible_v<T,
        decltype(std::get<I>(std::declval<Tuple>()))...>);
#if __cpp_lib_reference_from_temporary >= 202202L
    if constexpr (std::tuple_size_v<std::remove_reference_t<Tuple>> == 1) {
        using tuple_first_t = decltype(std::get<0>(std::declval<Tuple>()));
        static_assert(!std::reference_constructs_from_temporary_v<T, tuple_first_t>);
    }
#endif
    return std::make_unique<T>(std::get<I>(std::forward<Tuple>(t))...);
}
} // namespace detail

template<class T, class Tuple>
constexpr std::unique_ptr<T> make_new_from_tuple(Tuple&& t)
{
    return detail::make_new_from_tuple_impl<T>(std::forward<Tuple>(t),
        std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tuple>>>{});
}

struct A
{
    int i_; double d_; std::string s_;

    A( int i, double d, const std::string& s ) : i_(i), d_(d), s_(s) {}
};

int main()
{
    auto aTuple = std::make_tuple( 1, 1.5, std::string("Hello") );

    auto a = make_new_from_tuple<A>(std::move(aTuple));
}
Run Code Online (Sandbox Code Playgroud)

或者使用原始指针:

#include <string>
#include <memory>

namespace detail {
template<class T, class Tuple, std::size_t... I>
constexpr T* make_new_from_tuple_impl(Tuple&& t, std::index_sequence<I...>)
{
    static_assert(std::is_constructible_v<T,
        decltype(std::get<I>(std::declval<Tuple>()))...>);
#if __cpp_lib_reference_from_temporary >= 202202L
    if constexpr (std::tuple_size_v<std::remove_reference_t<Tuple>> == 1) {
        using tuple_first_t = decltype(std::get<0>(std::declval<Tuple>()));
        static_assert(!std::reference_constructs_from_temporary_v<T, tuple_first_t>);
    }
#endif
    return new T(std::get<I>(std::forward<Tuple>(t))...);
}
} // namespace detail

template<class T, class Tuple>
constexpr T* make_new_from_tuple(Tuple&& t)
{
    return detail::make_new_from_tuple_impl<T>(std::forward<Tuple>(t),
        std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tuple>>>{});
}

struct A
{
    int i_; double d_; std::string s_;

    A( int i, double d, const std::string& s ) : i_(i), d_(d), s_(s) {}
};

int main()
{
    auto aTuple = std::make_tuple( 1, 1.5, std::string("Hello") );

    auto a = make_new_from_tuple<A>(std::move(aTuple));
}
Run Code Online (Sandbox Code Playgroud)


for*_*818 9

您可以使用std::apply。它从元组中解压参数并将它们传递给可调用对象。您只需要包装构造函数。

#include <tuple>
#include <string>

struct A
{
    int i_; double d_; std::string s_;

    A( int i, double d, const std::string& s ) : i_(i), d_(d), s_(s) {}
};


int main() {
    auto aTuple = std::make_tuple( 1, 1.5, std::string("Hello") );
    A* a = std::apply( [](int i,double d,const std::string& s) { return new A(i,d,s);},aTuple);
}
Run Code Online (Sandbox Code Playgroud)

为了简洁起见,省略了完美转发。


Art*_*yer 8

只需用new它调用:

T* obj = new auto(std::make_from_tuple<T>( { Args... args } ));

// unique ptr
std::unique_ptr obj{new auto(std::make_from_tuple<T>({ Args... args }))};

// shared ptr
std::shared_ptr obj{new auto(std::make_from_tuple<T>({ Args... args }))};

// doesn't work for make_shared unfortunately
auto obj = std::apply([](auto&&... args) {
    return std::make_shared<T>(std::forward<decltype(args)>(args)...);
}, { Args... args });
Run Code Online (Sandbox Code Playgroud)

因为make_from_tuple返回纯右值,所以这将直接在堆中构造对象,而不进行复制或移动。