c++ - 在编译时使整数序列唯一
问题描述
假设我有:
template<int... N>
class seq
{
};
template<int... N>
struct uniq{
using type = seq<N...>;
};
我需要以某种方式使序列独一无二,这样
std::is_same_v<uniq<1,2,2,2,3,3,3>::type, seq<1, 2, 3>>;
最终是真的。换句话说,使序列唯一,然后创建一个序列。
有没有办法在编译时实现这一点?
解决方案
使用std
使用<type_traits>
标准库,您可以像这样实现自己的:
#include <type_traits>
namespace detail
{
template<class, auto... Ns>
struct uniq_impl;
template<template<auto...> class T, auto... Ms, auto N, auto... Ns>
struct uniq_impl<T<Ms...>, N, Ns...> : std::conditional_t<
(... || (N == Ms)),
uniq_impl<T<Ms...>, Ns...>,
uniq_impl<T<Ms..., N>, Ns...>>
{
};
template<template<auto...> class T, auto... Ms>
struct uniq_impl<T<Ms...>>
{
using type = T<Ms...>;
};
} // namespace detail
template<int... Ns>
class seq
{
};
template<int... Ns>
using uniq = detail::uniq_impl<seq<>, Ns...>;
static_assert(std::is_same_v<typename uniq<1,2,2,2,3,3,3>::type, seq<1, 2, 3>>);
uniq_impl
工作原理是从一个空seq<>
的参数包和 的参数包开始auto... Ns
,然后使用模板特化一次一个地取出参数包的前面
template<template<auto...> class T, auto... Ms, auto N, auto... Ns>
struct uniq_impl<T<Ms...>, N, Ns...> : std::conditional_t<
(... || (N == Ms)),
uniq_impl<T<Ms...>, Ns...>,
uniq_impl<T<Ms..., N>, Ns...>>
{
};
它检查是否N
在使用折叠表达式的集合中,并决定是auto... Ms
使用折叠表达式N
推入Ms
还是丢弃它std::conditional_t
。一旦auto... Ns
为空,则使用专业化
template<template<auto...> class T, auto... Ms>
struct uniq_impl<T<Ms...>>
{
using type = T<Ms...>;
};
标记生成的唯一值容器。在 godbolt.org 上试用:演示。
使用boost::mp11
正如其他人指出的那样,您可以将算法委托给boost::mp11::mp_unique
,但因为它适用于类型而不是值,您需要将值包装和解包std::integral_constant
才能使用这种方法:
#include <boost/mp11/algorithm.hpp>
namespace detail
{
template<template<auto...> class T, auto... Ns>
class uniq_impl
{
static boost::mp11::mp_list<std::integral_constant<decltype(Ns), Ns>...> types();
template <class L>
static boost::mp11::mp_unique<L> transform(L);
template<class... Ts, auto... Ms>
static T<Ms...> values(boost::mp11::mp_list<std::integral_constant<Ts, Ms>...>);
public:
using type = decltype(values(transform(types())));
};
} // namespace detail
template<int... Ns>
class seq
{
};
template<int... Ns>
using uniq = detail::uniq_impl<seq, Ns...>;
static_assert(std::is_same_v<typename uniq<1,2,2,2,3,3,3>::type, seq<1, 2, 3>>);
在 godbolt.org 上试用:演示。
推荐阅读
- image - 鱼眼图像到等角矩形图像投影
- c# - 创建新控制器时出现 VS 样板错误
- vba - 如何使用 VBA IE 自动化单击 div 下拉菜单
- python - 将列表的元素从 str 更改为 int?
- c# - “Webhook 的签名不在 Stripe-Signature 标头中。”
- python - 如何使用 Scipy 在 Python 中执行离散数据的数值积分(有限制)?
- ios - XCode 缺少“近场通信标签读取”功能
- python - 在字符串 Python 上查找最大连续出现次数
- flutter - 如何从 api 中的数据中搜索 [flutter]
- select - 如何使用列作为输入参数在 Azure 突触中创建 UDF 并返回一个表?