从向量的元素初始化结构

时间:2021-06-03 19:09:44

标签: c++ vector struct initialization

我想知道是否可以使用向量作为向量的初始值设定项列表。所以,如果我有

struct somedata{
    string str1;
    string str2;
}

struct moredata{
    string str1;
    string str2;
    string str3;
}

template<class Dataholder>
Dataholder queryUser(args){
    auto vec = get_vector_from_user(args)
    Dataholder dat{vec}; // The elements of vec become the structured variables in dat.
    return dat;
}

因此,当调用 get_vector_from_user() 时,用户可能会输入 2 或 3 个字符串。但是,我知道程序员将始终使用模板 queryUser,并且 vec 中的元素数量与 Dataholder 模板中的字符串数量相同。是否可以使用向量的成员初始化结构?谢谢!

2 个答案:

答案 0 :(得分:4)

对于有问题的类,编写一个接受 std::vector 的构造函数,或者直接在函数模板中包含逻辑:

struct somedata{
    string str1;
    string str2;
    somedata(const std::vector& vec) : str1(vec[0]), str2(vec[1]){
        
    }
}

struct moredata{
    string str1;
    string str2;
    string str3;
    moredata(const std::vector& vec) : str1(vec[0]), str2(vec[1]), str3(vec[2]){
        
    }
}

template<class Dataholder>
Dataholder queryUser(args){
    auto vec = get_vector_from_user(args)
    Dataholder dat{vec}; // The elements of vec become the structured variables in dat.
    return dat;
}

只需确保添加一个检查以断言向量中的元素数量正确。

答案 1 :(得分:3)

是的,这是可能的。枚举结构成员需要复杂的模板,并且可能需要代码生成,因为您可能需要为每个特定数量的结构成员提供样板代码。幸运的是,有一个图书馆可以做到这一点。看Boost.PFR,又名magic_get

它的界面模仿std::tuple的界面,所以很容易使用。

两个主要限制是:

  • 您的结构必须是聚合(即不能有自定义构造函数等)
  • 没有办法获取会员名

您还需要一个编译时 for 循环:

template <typename Integer, Integer ...I, typename F>
constexpr void constexpr_for_each(std::integer_sequence<Integer, I...>, F &&func)
{
    (func(std::integral_constant<Integer, I>{}) , ...);
}

template <auto N, typename F>
constexpr void constexpr_for(F &&func)
{
    if constexpr (N > 0)
        constexpr_for_each(std::make_integer_sequence<decltype(N), N>{}, std::forward<F>(func));
}

现在你可以这样做:

struct A
{
    std::string x;
    std::string y;
    std::string z;
};

int main()
{
    std::vector<std::string> vec = {"a", "b", "c"};
    if (vec.size() != boost::pfr::tuple_size_v<A>)
        throw std::runtime_error("Wrong vector size.");
    A a;
    constexpr_for<boost::pfr::tuple_size_v<A>>([&](auto index)
    {
        constexpr auto i = index.value;
        static_assert(std::is_same_v<std::string, boost::pfr::tuple_element_t<i, A>>);
        boost::pfr::get<i>(a) = vec[i];
    });

    std::cout << a.x << ' ' << a.y << ' ' << a.z << '\n'; // a b c
}

Run on gcc.godbolt.org