How to emulate C array initialization “int arr[] = { e1, e2, e3, … }” behaviour with std::array?

后端 未结 10 770
难免孤独
难免孤独 2020-11-22 17:23

(Note: This question is about not having to specify the number of elements and still allow nested types to be directly initialized.)
This question discu

相关标签:
10条回答
  • 2020-11-22 18:04

    If std::array is not a constraint and if you have Boost, then take a look at list_of(). This is not exactly like C type array initialization that you want. But close.

    0 讨论(0)
  • 2020-11-22 18:06

    С++17 compact implementation.

    template <typename... T>
    constexpr auto array_of(T&&... t) {
        return std::array{ static_cast<std::common_type_t<T...>>(t)... };
    }
    
    0 讨论(0)
  • 2020-11-22 18:07

    C++11 will support this manner of initialization for (most?) std containers.

    0 讨论(0)
  • 2020-11-22 18:10

    I know it's been quite some time since this question was asked, but I feel the existing answers still have some shortcomings, so I'd like to propose my slightly modified version. Following are the points that I think some existing answers are missing.


    1. No need to rely on RVO

    Some answers mention that we need to rely on RVO to return the constructed array. That is not true; we can make use of copy-list-initialization to guarantee there will never be temporaries created. So instead of:

    return std::array<Type, …>{values};
    

    we should do:

    return {{values}};
    

    2. Make make_array a constexpr function

    This allow us to create compile-time constant arrays.

    3. No need to check that all arguments are of the same type

    First off, if they are not, the compiler will issue a warning or error anyway because list-initialization doesn't allow narrowing. Secondly, even if we really decide to do our own static_assert thing (perhaps to provide better error message), we should still probably compare the arguments' decayed types rather than raw types. For example,

    volatile int a = 0;
    const int& b = 1;
    int&& c = 2;
    
    auto arr = make_array<int>(a, b, c);  // Will this work?
    

    If we are simply static_asserting that a, b, and c have the same type, then this check will fail, but that probably isn't what we'd expect. Instead, we should compare their std::decay_t<T> types (which are all ints)).

    4. Deduce the array value type by decaying the forwarded arguments

    This is similar to point 3. Using the same code snippet, but don't specify the value type explicitly this time:

    volatile int a = 0;
    const int& b = 1;
    int&& c = 2;
    
    auto arr = make_array(a, b, c);  // Will this work?
    

    We probably want to make an array<int, 3>, but the implementations in the existing answers probably all fail to do that. What we can do is, instead of returning a std::array<T, …>, return a std::array<std::decay_t<T>, …>.

    There is one disadvantage about this approach: we can't return an array of cv-qualified value type any more. But most of the time, instead of something like an array<const int, …>, we would use a const array<int, …> anyway. There is a trade-off, but I think a reasonable one. The C++17 std::make_optional also takes this approach:

    template< class T > 
    constexpr std::optional<std::decay_t<T>> make_optional( T&& value );
    

    Taking the above points into account, a full working implementation of make_array in C++14 looks like this:

    #include <array>
    #include <type_traits>
    #include <utility>
    
    template<typename T, typename... Ts>
    constexpr std::array<std::decay_t<T>, 1 + sizeof... (Ts)>
    make_array(T&& t, Ts&&... ts)
        noexcept(noexcept(std::is_nothrow_constructible<
                    std::array<std::decay_t<T>, 1 + sizeof... (Ts)>, T&&, Ts&&...
                 >::value))
    
    {
        return {{std::forward<T>(t), std::forward<Ts>(ts)...}};
    }
    
    template<typename T>
    constexpr std::array<std::decay<T>, 0> make_array() noexcept
    {
        return {};
    }
    

    Usage:

    constexpr auto arr = make_array(make_array(1, 2),
                                    make_array(3, 4));
    static_assert(arr[1][1] == 4, "!");
    
    0 讨论(0)
提交回复
热议问题