在 C++17 中定义可变坐标(元组)类型?
defining a variadic coordinate (tuple) type in C++17?
我想定义一个可变元组类型来表示坐标。例如,对于某些魔法类型:
template <unsigned int N>
struct CoordT {
typedef std::tuple<_some_magic_> coord_type;
};
我希望 CoordT<3>::coord_type
成为 3 维坐标类型:
std::tuple<double, double, double>
.
但是我不知道如何使用模板编程来生成N
重复double
s.
谁能帮忙解释一下怎么写?
使用std::make_integer_sequence
生成一个适当长度的包,然后将元素映射到双打:
template <size_t n>
struct TupleOfDoubles {
template <size_t... i>
static auto foo(std::index_sequence<i...>) {
return std::make_tuple(double(i)...);
}
using type = decltype(foo(std::make_index_sequence<n>{}));
};
来不及玩了?
如果您可以接受如下声明(不需要定义)可变参数模板函数
template <std::size_t ... Is>
constexpr auto toIndexSeq (std::index_sequence<Is...> a)
-> decltype(a);
并且coord_type
是在CoordT
特化中定义的,你可以这样写
template <std::size_t N,
typename = decltype(toIndexSeq(std::make_index_sequence<N>{}))>
struct CoordT;
template <std::size_t N, std::size_t ... Is>
struct CoordT<N, std::index_sequence<Is...>>
{ using coord_type = std::tuple<decltype((void)Is, 0.0)...>; };
以下是完整的C++14编译示例
#include <tuple>
#include <type_traits>
template <std::size_t ... Is>
constexpr auto toIndexSeq (std::index_sequence<Is...> a)
-> decltype(a);
template <std::size_t N,
typename = decltype(toIndexSeq(std::make_index_sequence<N>{}))>
struct CoordT;
template <std::size_t N, std::size_t ... Is>
struct CoordT<N, std::index_sequence<Is...>>
{ using coord_type = std::tuple<decltype((void)Is, 0.0)...>; };
int main()
{
using t0 = std::tuple<double, double, double, double>;
using t1 = typename CoordT<4u>::coord_type;
static_assert( std::is_same<t0, t1>::value, "!" );
}
如果您实际上不需要 std::tuple
,而只需要像元组一样的东西,请使用 std::array
:
template <unsigned int N>
struct CoordT {
typedef std::array<double, N> coord_type;
};
std::array
有 std::get<I>
, std::tuple_size
, and std::tuple_element
. Most library and language facilities which accept a tuple-like element will support std::array
, such as std::apply
and structured bindings.
的重载
一种非常简洁的方法是使用 std::tuple_cat
and std::array
:
template <unsigned int N>
struct CoordT {
using coord_type = decltype(std::tuple_cat(std::array<double, N>{}));
};
std::tuple_cat
是 allowed to support tuple-like types such as std::array
, but not guaranteed. However, every implementation I checked supports this.
我想定义一个可变元组类型来表示坐标。例如,对于某些魔法类型:
template <unsigned int N>
struct CoordT {
typedef std::tuple<_some_magic_> coord_type;
};
我希望 CoordT<3>::coord_type
成为 3 维坐标类型:
std::tuple<double, double, double>
.
但是我不知道如何使用模板编程来生成N
重复double
s.
谁能帮忙解释一下怎么写?
使用std::make_integer_sequence
生成一个适当长度的包,然后将元素映射到双打:
template <size_t n>
struct TupleOfDoubles {
template <size_t... i>
static auto foo(std::index_sequence<i...>) {
return std::make_tuple(double(i)...);
}
using type = decltype(foo(std::make_index_sequence<n>{}));
};
来不及玩了?
如果您可以接受如下声明(不需要定义)可变参数模板函数
template <std::size_t ... Is>
constexpr auto toIndexSeq (std::index_sequence<Is...> a)
-> decltype(a);
并且coord_type
是在CoordT
特化中定义的,你可以这样写
template <std::size_t N,
typename = decltype(toIndexSeq(std::make_index_sequence<N>{}))>
struct CoordT;
template <std::size_t N, std::size_t ... Is>
struct CoordT<N, std::index_sequence<Is...>>
{ using coord_type = std::tuple<decltype((void)Is, 0.0)...>; };
以下是完整的C++14编译示例
#include <tuple>
#include <type_traits>
template <std::size_t ... Is>
constexpr auto toIndexSeq (std::index_sequence<Is...> a)
-> decltype(a);
template <std::size_t N,
typename = decltype(toIndexSeq(std::make_index_sequence<N>{}))>
struct CoordT;
template <std::size_t N, std::size_t ... Is>
struct CoordT<N, std::index_sequence<Is...>>
{ using coord_type = std::tuple<decltype((void)Is, 0.0)...>; };
int main()
{
using t0 = std::tuple<double, double, double, double>;
using t1 = typename CoordT<4u>::coord_type;
static_assert( std::is_same<t0, t1>::value, "!" );
}
如果您实际上不需要 std::tuple
,而只需要像元组一样的东西,请使用 std::array
:
template <unsigned int N>
struct CoordT {
typedef std::array<double, N> coord_type;
};
std::array
有 std::get<I>
, std::tuple_size
, and std::tuple_element
. Most library and language facilities which accept a tuple-like element will support std::array
, such as std::apply
and structured bindings.
一种非常简洁的方法是使用 std::tuple_cat
and std::array
:
template <unsigned int N>
struct CoordT {
using coord_type = decltype(std::tuple_cat(std::array<double, N>{}));
};
std::tuple_cat
是 allowed to support tuple-like types such as std::array
, but not guaranteed. However, every implementation I checked supports this.