首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用std::向量初始化另一个std::向量的部分

使用std::向量初始化另一个std::向量的部分
EN

Stack Overflow用户
提问于 2021-08-25 20:13:27
回答 3查看 179关注 0票数 3

是否有方法“展开”初始化列表中的向量变量,以达到

代码语言:javascript
复制
std::vector<int> tmp1{1,1,2,3,5};
std::vector<int> tmp2{11,tmp1,99};
//tmp2 == {11,1,1,2,3,5,99}

我知道可以用std::复制或插入。想知道是否有列表初始化的方法来实现这一点。类似于python中的[11,*tmp1,99]

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2021-08-25 20:42:01

有了这个解决方案,您就可以得到与您想要的语法相近的东西。(是的,有些工作将在运行时完成)

代码语言:javascript
复制
#include <type_traits>
#include <vector>

namespace details
{
// recursive part
template<typename type_t, typename arg_t, typename...  args_t>
void append_to_vector(std::vector<type_t>& vec, arg_t value, args_t&&... values)
{
    if constexpr (std::is_same_v<arg_t, std::vector<type_t>>)
    {
        vec.insert(vec.end(), value.begin(), value.end());
    }
    else
    {
        vec.push_back(value);
    }

    if constexpr (sizeof...(args_t) > 0)
    {
        append_to_vector(vec, std::forward<args_t>(values)...);
    }
}
}

template<typename type_t, typename...  args_t>
std::vector<type_t> make_vector(args_t&&... values)
{
    std::vector<type_t> retval;
    if constexpr (sizeof...(args_t) > 0)
    {
        details::append_to_vector(retval, std::forward<args_t>(values)...);
    }
    return retval;
};

int main()
{
    auto tmp1 = make_vector<int>(1, 1, 2, 3, 5);
    auto tmp2 = make_vector<int>(11, tmp1, 99);
    return 0;
}
票数 6
EN

Stack Overflow用户

发布于 2021-08-26 15:06:35

一个选项可以是创建一个make_vector变量函数模板,以检查当前参数是否支持std::begin()。如果它支持std::begin(),则使用vectorinsert成员函数,否则,使用emplace_back。这将使从任何容器(带有正确的T)生成向量成为可能。

首先,要检查当前参数是否支持std::begin()的一种类型特征,以及检查它是否支持std::size()的类型。std::size()将用于计算最终vector所需的空间。当最终(或最小)的元素数量已知时,当填充vector时,保留空间常常被用来避免重新分配空间(和移动元素)--就像在本例中那样。

代码语言:javascript
复制
#include <iterator>
#include <type_traits>

template<typename T>
class has_begin {
    template<typename TT>
    static auto test(int) -> 
        decltype( std::begin(std::declval<const TT&>()), std::true_type() );

    template<typename>
    static auto test(...) -> std::false_type;

public:
    static constexpr bool value = decltype(test<T>(0))::value;
};

template<class T>
inline constexpr bool has_begin_v = has_begin<T>::value;
代码语言:javascript
复制
template<typename T>
class has_size {
    template<typename TT>
    static auto test(int) ->
        decltype( std::size(std::declval<const TT&>()), std::true_type() );

    template<typename>
    static auto test(...) -> std::false_type;

public:
    static constexpr bool value = decltype(test<T>(0))::value;
};

template<class T>
inline constexpr bool has_size_v = has_size<T>::value;

然后,实际的make_vector函数模板和帮助程序来计算实际大小,并确定如何处理一个特定的参数。

代码语言:javascript
复制
#include <utility>
#include <vector>

namespace detail {

template<class T, class Arg>
size_t make_vector_capacity(Arg&& arg) {
    if constexpr(std::is_same_v<T, std::remove_cv_t<std::remove_reference_t<Arg>>>) {
        // same type as in the vector, return 1
        return 1;
    } else if constexpr(has_size_v<Arg>) {
        // a container supporting std::size
        return std::size(arg);
    } else if constexpr(has_begin_v<Arg>) {
        // a container but not supporting std::size
        return std::distance(std::begin(arg), std::end(arg));
    } else {
        // fallback
        return 1;
    }
}

template<class T, class Arg>
void make_vector_helper(std::vector<T>& v, Arg&& arg) {
    if constexpr(std::is_same_v<T, std::remove_cv_t<std::remove_reference_t<Arg>>>) {
        // same type as in the vector, insert it as-is
        v.emplace_back(std::forward<Arg>(arg));
    } else if constexpr(has_begin_v<Arg>) {
        // arg supports std::begin, use insert
        v.insert(v.end(), std::begin(arg), std::end(arg));
    } else {
        // fallback
        v.emplace_back(std::forward<Arg>(arg));
    }
}
} // namespace detail
代码语言:javascript
复制
template<class T, class... Args>
std::vector<T> make_vector(Args&&... args) {
    std::vector<T> rv;

    // a fold expression to calculate the capacity needed:
    rv.reserve( (detail::make_vector_capacity<T>(args) + ...) );

    // a fold expression to call make_vector_helper for each argument
    (detail::make_vector_helper(rv, std::forward<Args>(args)), ...);

    return rv;
}

一个使用示例,混合不同的容器和std::string的单个值

代码语言:javascript
复制
#include <initializer_list>
#include <iostream>
#include <list>
#include <vector>
#include <string>

int main() {
    using namespace std::string_literals;

    const std::string arr[] = {"3"s, "4"s};
    const std::vector vec{"5"s, "6"s, "7"s , "8"s};
    const std::list list{"9"s,"10"s};
    auto init = {"13"s, "14"s, "15"s};

    const auto tmp2 = make_vector<std::string>("1"s, "2"s, arr, vec, list,
                                               "11"s, "12"s, init );

    for(const auto& e: tmp2) std::cout << e <<' ';
}

输出:

代码语言:javascript
复制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 

演示

票数 3
EN

Stack Overflow用户

发布于 2021-08-25 20:42:23

不,这是不可能的,但您可以让一个允许这样做的助手:

代码语言:javascript
复制
#include <array>
#include <type_traits>

// Containerize MaybeContainer type if it not equal to T.
template<typename T, typename MaybeContainer>
using impl_containerize =  std::conditional_t<std::is_same_v<T,std::decay_t<MaybeContainer>>,std::array<T,1>,MaybeContainer>;

// Concatenate containers
template<typename Container,typename...Args>
Container impl_construct(Args&&...args){
    Container c;
    (c.insert(c.end(), std::begin(args), std::end(args)), ...);
    return c;
}

template<typename Container,typename...Args>
Container construct(Args&&...args){
    using T = typename Container::value_type;
    return impl_construct<Container, impl_containerize<T,Args>...>({std::forward<Args>(args)}...);
}

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> tmp1{1,3,5,7,9};
    const auto tmp2 = construct<std::vector<int>>(2,4,tmp1,6);
    for(const auto& e: tmp2){
        std::cout<<e<<' ';
    }
}

输出

代码语言:javascript
复制
2 4 1 3 5 7 9 6 
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68929308

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档