检查模拟参数在同类参数包中是否出现两次以上

时间:2017-01-06 10:40:27

标签: c++ c++11 templates variadic-templates template-meta-programming

我需要检查传递给函数的任何参数是否出现两次以上。基本上,我想要以下行为

no_unique<0,1,0,1,0,1>::value // returns 2

我知道finding the number of uniques上有一个问题,但它没有回答我的问题,因为该问题的解决方案返回了例如

C++11

但它没有说参数是出现一次,两次还是三次。

如何在>>> grid = [] >>> def solve(grid) ... global grid ... 中实现这一目标?

5 个答案:

答案 0 :(得分:3)

效率不高但您可以使用以下内容:

#include <algorithm>
#include <type_traits>

template <size_t S, size_t... Sizes>
struct count;

template <size_t S>
struct count<S>: std::integral_constant<size_t, 0> {};

template <size_t S1, size_t... Sizes>
struct count<S1, S1, Sizes...>: 
    std::integral_constant<size_t, 1 + count<S1, Sizes...>{}> {};

template <size_t S1, size_t S2, size_t... Sizes>
struct count<S1, S2, Sizes...>: 
    count<S1, Sizes...> {};

template <size_t...>
struct max_count;

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

template <size_t S, size_t... Sizes>
struct max_count<S, Sizes...>:
    std::integral_constant<size_t, std::max(1 + count<S, Sizes...>{},
                                            max_count<Sizes...>::value)> { };

template <size_t... Sizes>
struct no_more_than_two: std::integral_constant<bool, max_count<Sizes...>{} <= 2> { };

static_assert(no_more_than_two<0,1,0,1>{}, "");
static_assert(!no_more_than_two<2,0,1,2,2>{}, "");
static_assert(!no_more_than_two<5,5,5>{}, "");

首先检索任何值的最大出现次数,然后将其与2进行比较。

如果您只有C ++ 11(不是C ++ 14),请将std::max替换为自定义ct_max

template <typename T>
constexpr const T& ct_max(T const& t1, T const& t2) {
    return t1 < t2 ? t2 : t1;
}

答案 1 :(得分:2)

滥用多重继承的答案:

#include <utility>
#include <type_traits>

template <std::size_t I>
struct wrap {};

template <std::size_t ... Is>
struct derived : wrap<Is>...
{
};
template <>
struct derived<> {
};

template <typename, typename, std::size_t...>
struct appearance_impl;

template <std::size_t... I2, std::size_t... I1, std::size_t I, std::size_t...Is>
struct appearance_impl<derived<I2...>, derived<I1...>, I, Is...>
    : std::conditional<
        std::is_base_of<wrap<I>, derived<I2...>>::value, // If I in I2 => false
        std::false_type,
        typename std::conditional<
            std::is_base_of<wrap<I>, derived<I1...>>::value, // else if I in I1, add I to I2
            appearance_impl<derived<I, I2...>, derived<I1...>, Is...>,
            appearance_impl<derived<I2...>, derived<I, I1...>, Is...>
            >::type
        >::type
{
};

template <typename D2, typename D1>
struct appearance_impl<D2, D1> : std::true_type {};


template <std::size_t ...Is>
struct appearance : appearance_impl<derived<>, derived<>, Is...>::type { };

int main() {
    static_assert(appearance<0,1,0,1>::value, "");
    static_assert(!appearance<2,0,1,2,2>::value, "");
    static_assert(!appearance<5,5,5>::value, "");
}

Demo

答案 2 :(得分:1)

这是一个更长的时间,但它应该非常有效,并且它避免了很多聪明。

// Map integers to types.
template< int i >
using intc = std::integral_constant< int, i >;

// Increment a type-integer.
template< typename intc >
using inc_intc = std::integral_constant< int, intc::value + 1 >;

// Count the appearances of an integer in a sequence.
template< int ... >
struct appearances { // Base case of induction: return zero for every value.
    template< int i >
    static intc< 0 > count( intc< i > );
};

// Recursive case: Add one to the base class count.
template< int i, int ... rem >
struct appearances< i, rem ... >
    : appearances< rem ... > {
    typedef appearances< rem ... > base;
    using base::count;

    static inc_intc< decltype( base::count( intc< i >{} ) ) >
        count( intc< i > );
};

// Find the sequences in question with early exit.
template< typename acc, typename seq, typename = void >
struct no_triple_occurrence_impl // Base case: empty sequence, no triples.
    : std::true_type {};

// Early exit case: found two instances of the next i.
template< typename acc, int i, int ... rem >
struct no_triple_occurrence_impl<
    acc,
    std::integer_sequence< int, i, rem ... >,
    std::enable_if_t< decltype(
        acc::count( intc< i >{} )
    ){} >= 2 >
> : std::false_type {};

// Recursive case: add the next i to the counter.
template< int ... done, int i, int ... rem >
struct no_triple_occurrence_impl<
    appearances< done ... >,
    std::integer_sequence< int, i, rem ... >,
    std::enable_if_t< decltype(
        appearances< done ... >::count( intc< i >{} )
    ){} < 2 >
> : no_triple_occurrence_impl<
    appearances< i, done ... >, // Keep done... at the end for memoization.
    std::integer_sequence< int, rem ... >
>::type {};

template< int ... seq >
constexpr bool no_triple_occurrence
    = no_triple_occurrence_impl<
        appearances<>,
        std::integer_sequence< int, seq ... >
    >::value; 

on Coliru。)

答案 3 :(得分:1)

我也可以玩吗?

以下是我的解决方案,主要基于部分模板专业化。

#include <iostream>

using IType = int; // or long? or unsigned? or size_t?

template <typename IT, IT ...>
struct intSeq
 { };

template <typename, typename, std::size_t>
struct no_more_than_val;

template <typename IT, IT I0, std::size_t M, IT Val, IT ... Is>
struct no_more_than_val<intSeq<IT, I0, Is...>, intSeq<IT, Val>, M>
 { static constexpr bool value
    { no_more_than_val<intSeq<IT, Is...>, intSeq<IT, Val>, M>::value }; };

template <typename IT, IT Val, std::size_t M, IT ... Is>
struct no_more_than_val<intSeq<IT, Val, Is...>, intSeq<IT, Val>, M>
 { static constexpr bool value
    { no_more_than_val<intSeq<IT, Is...>, intSeq<IT, Val>, M-1U>::value }; };

template <typename IT, IT I0, IT ... Is>
struct no_more_than_val<intSeq<IT, I0, Is...>, intSeq<IT, I0>, 0U>
 { static constexpr bool value { false }; };

template <typename IT, std::size_t M, IT Val>
struct no_more_than_val<intSeq<IT>, intSeq<IT, Val>, M>
 { static constexpr bool value { true }; };


template <typename, std::size_t>
struct no_more_than_list;

template <typename IT, std::size_t M>
struct no_more_than_list<intSeq<IT>, M>
 { static constexpr bool value { true }; };

template <typename IT, IT I0, IT ... Is>
struct no_more_than_list<intSeq<IT, I0, Is...>, 0U>
 { static constexpr bool value { false }; };

template <typename IT, std::size_t M, IT I0, IT ... Is>
struct no_more_than_list<intSeq<IT, I0, Is...>, M>
 {
   static constexpr bool value
    {    no_more_than_val<intSeq<IT, Is...>, intSeq<IT, I0>, M-1U>::value
      && no_more_than_list<intSeq<IT, Is...>, M>::value };
 };


template <IType ... Is>
struct appearance
   : public no_more_than_list<intSeq<IType, Is...>, 2U>
 { };


int main()
 {
   std::cout << appearance<0,1,0,1>::value << std::endl;   // print 1
   std::cout << appearance<2,0,1,2,2>::value << std::endl; // print 0
   std::cout << appearance<5,5,5>::value << std::endl;     // print 0
 }

如果您可以使用C ++ 14,则可以使用std::integer_sequence代替intSeq。无论如何,您可以使用std::integral_constant<IT, Val>代替intSeq<IT, Val>

答案 4 :(得分:0)

使用boost.hana的简短且易读的版本:

#include <boost/hana/all_of.hpp>
#include <boost/hana/group.hpp>
#include <boost/hana/length.hpp>
#include <boost/hana/less.hpp>
#include <boost/hana/sort.hpp>
#include <boost/hana/tuple.hpp>
#include <boost/hana/type.hpp>

namespace hana = boost::hana;

template <int... ints>
struct appearance {
    static constexpr bool value =
        hana::all_of(
            hana::transform(
                hana::group(
                    hana::sort(
                        hana::make_tuple(hana::size_c<ints>...))),
                hana::length),
            hana::less.than(hana::size_c<3>));
};

On Coliru