查找参数包的唯一值的数量

rom*_*ric 4 c++ template-meta-programming c++11

给定具有可变参数的参数包,如何找到包中唯一值的数量.我正在寻找一些类似的东西

no_of_uniques<0,1,2,1,2,2>::value // should return 3
Run Code Online (Sandbox Code Playgroud)

我的基本实现看起来像这样

template <size_t ... all>
struct no_of_uniques;
// this specialisation exceeds -ftemplate-depth as it has no terminating condition
template <size_t one, size_t ... all>
struct no_of_uniques<one,all...> {
    static const size_t value = no_of_uniques<one,all...>::value;
};
template <size_t one, size_t two, size_t three>
struct no_of_uniques<one,two,three> {
    static const size_t value = (one==two && one==three && two==three) ? 1:
                                (one!=two && two==three) ? 2:
                                (one==two && one!=three) ? 2:
                                (one==three && two!=three) ? 2: 3;
};
template <size_t one, size_t two>
struct no_of_uniques<one,two> {
    static const size_t value = one==two ? 1: 2;
};
template <size_t one>
struct no_of_uniques<one> {
    static const size_t value = 1;
};
Run Code Online (Sandbox Code Playgroud)

在这里,我专门讨论了最多三个参数,但可以理解的是,代码随着参数的数量呈指数增长.我想meta单独使用一个STL没有第三方库的解决方案Boost.MPL.

类似的问题虽然在检查唯一类型的上下文中,而不是查找参数包的唯一值的数量,可以在这里找到:

检查可变参数模板参数的唯一性

在查找参数包的唯一值的数量的过程中,我们可能需要首先对包进行排序,并在此另一个问题中提供了一个很好的实现.

使用C++ 11可变参数模板在编译时快速排序

kmd*_*eko 10

这是一种简单的O(n ^ 2)方法

template <size_t...>
struct is_unique : std::integral_constant<bool, true> {};

template <size_t T, size_t U, size_t... VV>
struct is_unique<T, U, VV...> : std::integral_constant<bool, T != U && is_unique<T, VV...>::value> {};

template <size_t...>
struct no_unique : std::integral_constant<size_t, 0> {};

template <size_t T, size_t... UU>
struct no_unique<T, UU...> : std::integral_constant<size_t, is_unique<T, UU...>::value + no_unique<UU...>::value> {};
Run Code Online (Sandbox Code Playgroud)

所以使用你的例子:

no_unique<0, 1, 2, 1, 2, 2>::value; // gives 3
Run Code Online (Sandbox Code Playgroud)


T.C*_*.C. 6

其中大部分是我已经为不同的问题写的机器,剥夺了"计数"部分.

一个包含sizeof快捷方式的包:

template<class... Ts> struct pack { 
    static constexpr size_t size = sizeof...(Ts);
};
Run Code Online (Sandbox Code Playgroud)

将类型添加到一个类型的包中,但仅当它已经不存在时:

template<class T, class PT> struct do_push;
template<class T, class...Ts>
struct do_push<T, pack<Ts...>>{
   using type = std::conditional_t<std::disjunction_v<std::is_same<Ts, T>...>,
        pack<Ts...>,
        pack<T, Ts...>
        >;
};
template<class T, class PT> using push = typename do_push<T, PT>::type;
Run Code Online (Sandbox Code Playgroud)

现在制作一包独特的类型:

template<class P, class PT = pack<> >
struct unique_types_imp { using type = PT; };

template<class PT, class T, class... Ts>
struct unique_types_imp <pack<T, Ts...>, PT>
        : unique_types_imp <pack<Ts...>, push<T, PT>> {};

template<class P>
using unique_types = typename unique_types_imp<P>::type;
Run Code Online (Sandbox Code Playgroud)

最后:

template<size_t S>
using size_constant = std::integral_constant<size_t, S>;

template<size_t... all>
struct no_of_uniques{
     static constexpr size_t value = unique_types<pack<size_constant<all>...>>::size;
};
Run Code Online (Sandbox Code Playgroud)