简体   繁体   English

有没有一种可扩展的方法来从 C++ 中的数组初始化结构?

[英]Is there an extensible way to initialize a struct from an array in C++?

struct SomeStruct {
    int a;
    int b;
    int c;
    int d;
};

void main() {
    std::array<int, 4> arr {1, 2, 3, 4};
    SomeStruct someStruct { ??? }; // <------ Initialize with arr? (Ideal would be {arr})
}

As seen in the code example, is there some shortcut to initialize someStruct with arr?如代码示例中所示,是否有一些快捷方式可以使用 arr 初始化 someStruct? Instead of resorting to:而不是诉诸于:

    SomeStruct someStruct {arr[0], arr[1], arr[2], arr[3]};

You can use std::apply to create a parameter pack and use that in the initializer:您可以使用std::apply创建一个参数包并在初始化程序中使用它:

auto someStruct = std::apply([](auto&&... args){return SomeStruct{decltype(args)(args)...};}, arr);

You can put this in a function to use it comfortably:你可以把它放在一个函数中以舒适地使用它:

template<typename T, typename A>
constexpr T make_from_tuple_list_init(A&& a) {
    return std::apply([](auto&&... args){return T{decltype(args)(args)...};}, std::forward<A>(a));
}

Then use it as然后将其用作

auto someStruct = make_from_tuple_list_init<SomeStruct>(arr);

This requires C++17 and #include<tuple> , but can be implemented in earlier C++ versions (with some more effort) as well.这需要 C++17 和#include<tuple> ,但也可以在早期的 C++ 版本中实现(需要更多的努力)。 Also in C++17 this is guaranteed to use copy elision, so there will be only one SomeStruct constructed.同样在 C++17 中,这保证使用复制省略,因此只会构造一个SomeStruct Before C++17 some move constructions might be involved (although compilers were already permitted to and did implement return value optimization with the same effect).在 C++17 之前,可能会涉及一些移动构造(尽管编译器已经被允许并且确实实现了具有相同效果的返回值优化)。

std::apply also has the benefit that it works with every type that implements std::get and std::tuple_size , meaning that it will work for example with std::array , std::tuple , std::pair and other user-defined types with that interface. std::apply也有一个好处,它适用于实现std::getstd::tuple_size所有类型,这意味着它将适用于例如std::arraystd::tuplestd::pair和其他具有该接口的用户定义类型。

One might want to make two versions of this function, one that uses T{...} as above and one that uses T(...) , so that one is able to choose between list-initialization and direct-initialization.一个人可能想要制作这个函数的两个版本,一个使用上面的T{...} ,一个使用T(...) ,以便可以在列表初始化和直接初始化之间进行选择。

However, the T(...) version has been implemented in the standard library since C++17 as std::make_from_tuple .但是,自 C++17 以来,标准库中已将T(...)版本作为std::make_from_tuple In C++20, aggregate initialization will also work with parentheses, so std::make_from_tuple will work for your case then directly.在 C++20 中,聚合初始化也适用于括号,因此std::make_from_tuple将直接适用于您的情况。


For a C++14 implementation, take this example from cppreference's page on std::make_from_tuple :对于 C++14 实现,请从std::make_from_tuple上的 cppreference 页面获取此示例:

 namespace detail { template <class T, class Tuple, std::size_t... I> constexpr T make_from_tuple_impl( Tuple&& t, std::index_sequence<I...> ) { return T(std::get<I>(std::forward<Tuple>(t))...); } } // namespace detail template <class T, class Tuple> constexpr T make_from_tuple( Tuple&& t ) { return detail::make_from_tuple_impl<T>(std::forward<Tuple>(t), std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tuple>>>{}); }

and replace std::tuple_size_v<...> with std::tuple_size<...>::value .并将std::tuple_size_v<...>替换为std::tuple_size<...>::value

This is for the T(...) version.这是针对T(...)版本的。 You would need to replace T(...) with T{...} to get the T{...} version I implemented above.您需要将T(...)替换为T{...}才能获得我上面实现的T{...}版本。

You can define a constructor taking a pair of iterators.您可以定义一个带有一对迭代器的构造函数。 Sometimes simplicity wins over flexibility.有时,简单胜过灵活性。

#include <array>

struct SomeStruct {
    int a;
    int b;
    int c;
    int d;

    template<class InputIt>
    SomeStruct(InputIt begin, InputIt end)
    {
        if (begin != end) a = *begin++;
        if (begin != end) b = *begin++;
        if (begin != end) c = *begin++;
        if (begin != end) d = *begin++;
    }
};

Demo: https://coliru.stacked-crooked.com/a/7e235a8022b048ac演示: https : //coliru.stacked-crooked.com/a/7e235a8022b048ac

You can use one of the Memory Transfer functions.您可以使用其中一种内存传输功能。 {memcpy, CopyMemory} {memcpy, CopyMemory}

this is an example:这是一个例子:

#include <iostream>
#include <array>
#include <string.h>

using namespace std;

int main()
{
   array<int,4> ar = {1,2,3,4};

   struct myStruct
   {
      int a;
      int b;
      int c;
      int d;
   };

 myStruct stc;

memcpy(&stc, ar.data(), sizeof(stc));


cout << "My struct elements are: " << stc.a << " - " << stc.b << " - "<< stc.c << " - " << stc.d << endl;
return 0; 
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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