如何写一个类似于 std::make_tuple 的 make_vector?
How do I write a make_vector similar to std::make_tuple?
而不是像这样创建向量:
std::vector<int> v1{1,2,3};
std::vector<double> v2{1.1,2.2,3.3};
std::vector<Object> v3{Object{},Object{},Object{}};
我想用通用函数创建它们:
auto v1 = make_vector(1,2,3);
auto v2 = make_vector(1.1,2.2,3.3);
auto v3 = make_vector(Object{},Object{},Object{});
类似于std::make_pair and std::make_tuple,这是我对矢量的尝试:
#include <iostream>
#include <vector>
#include <utility>
template <typename... T>
auto make_vector(T&&... args)
{
using first_type = typename std::tuple_element<0, std::tuple<T...>>::type;
return std::vector<first_type>{std::forward<T>(args)...};
}
它可以编译,但是当我尝试使用它时:
auto vec = make_vector(1,2,3);
m.cpp: In instantiation of ‘auto make_vector(T&& ...) [with T = {int, int, int}]’:
m.cpp:16:30: required from here
m.cpp:8:78: error: invalid use of incomplete type ‘class std::tuple_element<0ul, std::tuple<int, int, int> >’
using first_type = typename std::tuple_element<0, std::tuple<T...>>::type;
^
In file included from m.cpp:3:0:
/usr/include/c++/5/utility:85:11: note: declaration of ‘class std::tuple_element<0ul, std::tuple<int, int, int> >’
class tuple_element;
^
m.cpp:9:60: error: invalid use of incomplete type ‘class std::tuple_element<0ul, std::tuple<int, int, int> >’
return std::vector<first_type>{std::forward<T>(args)...};
^
In file included from m.cpp:3:0:
/usr/include/c++/5/utility:85:11: note: declaration of ‘class std::tuple_element<0ul, std::tuple<int, int, int> >’
class tuple_element;
^
m.cpp: In function ‘int main()’:
m.cpp:16:30: error: ‘void v1’ has incomplete type
auto v1 = make_vector(1,2,3);
如何制作通用例程,
使用第一个参数的第一个类型来实例化向量?
如何将参数作为初始化值转发给向量?
就像你做的那样 - gcc 和 msvc 都用一个很小的 #include <tuple>
.
编译你的函数
因为你不能用它来创建一个空向量,我们可以通过提供一个额外的模板参数来避免 tuple
依赖:
template <class T0, class... Ts>
auto make_vector(T0&& first, Ts&&... args)
{
using first_type = std::decay_t<T0>;
return std::vector<first_type>{
std::forward<T0>(first),
std::forward<Ts>(args)...
};
}
如果 first
作为左值传入,它还有工作的额外好处。
让我们跟随 make_array
的脚步,允许用户明确指定 return 类型,或使用由 std::common_type
确定的 return 类型。
template<class T> struct identity { using type = T; };
template<class D, class... Ts>
struct ret : identity<D> {};
template<class... Ts>
struct ret<void, Ts...> : std::common_type<Ts...> {};
template<class D, class... Ts>
using ret_t = typename ret<D, Ts...>::type;
template<class D = void, class... Ts>
std::vector<ret_t<D, Ts...>> make_vector(Ts&&... args) {
std::vector<ret_t<D, Ts...>> ret;
ret.reserve(sizeof...(args));
using expander = int[];
(void) expander{ ((void)ret.emplace_back(std::forward<Ts>(args)), 0)..., 0 };
return ret;
}
完美转发的使用表明您要消除不必要的复制;这与使用需要每个元素的副本的 initalizer_list
构造函数不一致。因此,上面的代码 reserve
是 space 的正确数量,然后 emplace_back
使用通常的包扩展技巧将元素一个一个地添加。
如果您不想启用显式转换,则可以使用 push_back
来代替,但代价是可能会导致类型不匹配。但是,在这种情况下,类型要么由用户明确指定,要么通过 common_type
隐式转换推导出来,因此 emplace_back
可能就可以了。
而不是像这样创建向量:
std::vector<int> v1{1,2,3};
std::vector<double> v2{1.1,2.2,3.3};
std::vector<Object> v3{Object{},Object{},Object{}};
我想用通用函数创建它们:
auto v1 = make_vector(1,2,3);
auto v2 = make_vector(1.1,2.2,3.3);
auto v3 = make_vector(Object{},Object{},Object{});
类似于std::make_pair and std::make_tuple,这是我对矢量的尝试:
#include <iostream>
#include <vector>
#include <utility>
template <typename... T>
auto make_vector(T&&... args)
{
using first_type = typename std::tuple_element<0, std::tuple<T...>>::type;
return std::vector<first_type>{std::forward<T>(args)...};
}
它可以编译,但是当我尝试使用它时:
auto vec = make_vector(1,2,3);
m.cpp: In instantiation of ‘auto make_vector(T&& ...) [with T = {int, int, int}]’:
m.cpp:16:30: required from here
m.cpp:8:78: error: invalid use of incomplete type ‘class std::tuple_element<0ul, std::tuple<int, int, int> >’
using first_type = typename std::tuple_element<0, std::tuple<T...>>::type;
^
In file included from m.cpp:3:0:
/usr/include/c++/5/utility:85:11: note: declaration of ‘class std::tuple_element<0ul, std::tuple<int, int, int> >’
class tuple_element;
^
m.cpp:9:60: error: invalid use of incomplete type ‘class std::tuple_element<0ul, std::tuple<int, int, int> >’
return std::vector<first_type>{std::forward<T>(args)...};
^
In file included from m.cpp:3:0:
/usr/include/c++/5/utility:85:11: note: declaration of ‘class std::tuple_element<0ul, std::tuple<int, int, int> >’
class tuple_element;
^
m.cpp: In function ‘int main()’:
m.cpp:16:30: error: ‘void v1’ has incomplete type
auto v1 = make_vector(1,2,3);
如何制作通用例程,
使用第一个参数的第一个类型来实例化向量?
如何将参数作为初始化值转发给向量?
就像你做的那样 - gcc 和 msvc 都用一个很小的 #include <tuple>
.
因为你不能用它来创建一个空向量,我们可以通过提供一个额外的模板参数来避免 tuple
依赖:
template <class T0, class... Ts>
auto make_vector(T0&& first, Ts&&... args)
{
using first_type = std::decay_t<T0>;
return std::vector<first_type>{
std::forward<T0>(first),
std::forward<Ts>(args)...
};
}
如果 first
作为左值传入,它还有工作的额外好处。
让我们跟随 make_array
的脚步,允许用户明确指定 return 类型,或使用由 std::common_type
确定的 return 类型。
template<class T> struct identity { using type = T; };
template<class D, class... Ts>
struct ret : identity<D> {};
template<class... Ts>
struct ret<void, Ts...> : std::common_type<Ts...> {};
template<class D, class... Ts>
using ret_t = typename ret<D, Ts...>::type;
template<class D = void, class... Ts>
std::vector<ret_t<D, Ts...>> make_vector(Ts&&... args) {
std::vector<ret_t<D, Ts...>> ret;
ret.reserve(sizeof...(args));
using expander = int[];
(void) expander{ ((void)ret.emplace_back(std::forward<Ts>(args)), 0)..., 0 };
return ret;
}
完美转发的使用表明您要消除不必要的复制;这与使用需要每个元素的副本的 initalizer_list
构造函数不一致。因此,上面的代码 reserve
是 space 的正确数量,然后 emplace_back
使用通常的包扩展技巧将元素一个一个地添加。
push_back
来代替,但代价是可能会导致类型不匹配。但是,在这种情况下,类型要么由用户明确指定,要么通过 common_type
隐式转换推导出来,因此 emplace_back
可能就可以了。