2

Мне нужно проверить, появляется ли какой-либо из параметров, переданных функции, более двух раз. По существу, я хочу следующее поведениеПроверьте, не превышает ли параметр шаблона более одного раза в однородном пакете параметров

appearance<0,1,0,1>::value // should return true 
appearance<2,0,1,2,2>::value // should return false 
appearance<5,5,5>::value // should return false 

Я знаю, есть вопрос о finding the number of uniques, но это не ответ на мой вопрос, так как решения этого вопроса возврата, например

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

Но это делает не говорите, если параметр появился один, два или три раза.

Как достичь этого в C++11?

+0

Возможный дубликат [Найти число уникальных значений параметров пакета] (http://stackoverflow.com/questions/ 37150354/find-number-of-unique-values-of-a-parameter-pack) – gbjbaanb

+0

Потому что в '<0,1,0,1>' '0' и' 1' появляются только дважды, тогда как в '<2,0,1,2,2>' '2 появляется три раза. Я хочу проверить, появляется ли параметр более ** дважды **. –

+0

Несомненно, но принцип тот же, что ответ дает вам все, что вам нужно знать, за исключением того, как считать больше 2. – gbjbaanb

ответ

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; 
} 
+0

isnt 'std :: max' функция времени выполнения? –

+1

@TasamFarkie Это функция 'constexpr', поскольку C++ 14 (http://en.cppreference.com/w/cpp/algorithm/max), но если вы хотите чистую версию C++ 11, вы можете легко создать твой собственный. – Holt

+0

Отлично. Большое спасибо. –

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

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.)

1

Могу ли я играть слишком?

Следующее - мое решение, healvely основано на частичной специализированной специализации.

#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>.

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