是否有方法“展开”初始化列表中的向量变量,以达到
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]
发布于 2021-08-25 20:42:01
有了这个解决方案,您就可以得到与您想要的语法相近的东西。(是的,有些工作将在运行时完成)
#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;
}发布于 2021-08-26 15:06:35
一个选项可以是创建一个make_vector变量函数模板,以检查当前参数是否支持std::begin()。如果它支持std::begin(),则使用vector的insert成员函数,否则,使用emplace_back。这将使从任何容器(带有正确的T)生成向量成为可能。
首先,要检查当前参数是否支持std::begin()的一种类型特征,以及检查它是否支持std::size()的类型。std::size()将用于计算最终vector所需的空间。当最终(或最小)的元素数量已知时,当填充vector时,保留空间常常被用来避免重新分配空间(和移动元素)--就像在本例中那样。
#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;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函数模板和帮助程序来计算实际大小,并确定如何处理一个特定的参数。
#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 detailtemplate<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的单个值
#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 <<' ';
}输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 发布于 2021-08-25 20:42:23
不,这是不可能的,但您可以让一个允许这样做的助手:
#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<<' ';
}
}输出
2 4 1 3 5 7 9 6 https://stackoverflow.com/questions/68929308
复制相似问题