2

Je dois vérifier si l'un des paramètres transmis à une fonction apparaît plus de deux fois. Essentiellement, je veux que le comportement suivantVérifier si un paramètre de modèle apparaît plus de deux fois dans un paquet de paramètres homogène

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 

Je sais qu'il ya une question sur finding the number of uniques, mais il ne répond pas à ma question, puisque les solutions à ce retour de la question par exemple

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

Mais il ne ne dit pas si le paramètre est apparu une fois, deux fois ou trois fois.

Comment puis-je obtenir ceci en C++11?

+0

double possible de [Trouver nombre de valeurs uniques d'un pack de paramètres] (http://stackoverflow.com/questions/ 37150354/find-number-of-unique-values-of-a-parameter-pack) – gbjbaanb

+0

Parce que dans '<0,1,0,1>' '0' et '1' n'apparaissent que deux fois alors que dans' <2,0,1,2,2> '' 2' apparaît trois fois. Je veux vérifier si un paramètre apparaît plus de ** deux fois **. –

+0

Bien sûr, mais le principe est le même, cette réponse vous donne tout ce que vous devez savoir, sauf comment compter plus de 2. – gbjbaanb

Répondre

3

Pas vraiment efficace, mais vous pouvez utiliser les éléments suivants:

#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>{}, ""); 

Vous devez d'abord récupérer le nombre maximum d'occurrences d'une valeur, puis le comparer à 2.

Si vous avez seulement C++ 11 (pas C++ 14), remplacez std::max par une coutume ct_max:

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

n'est pas 'std :: max' une fonction d'exécution? –

+1

@TasamFarkie C'est une fonction 'constexpr' depuis C++ 14 (http://en.cppreference.com/w/cpp/algorithm/max), mais si vous voulez une version pure de C++ 11, vous pouvez facilement créer le tien. – Holt

+0

Super. Merci beaucoup. –

2

Ma réponse par abus héritage multiple:

#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

Ceci est un peu plus longtemps, mais il devrait être assez efficace et il évite beaucoup d'esprit.

// 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

Puis-je jouer aussi?

Ce qui suit est ma solution, basée essentiellement sur la spécialisation partielle de modèle.

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

Si vous pouvez utiliser C++ 14, vous pouvez utiliser std::integer_sequence au lieu de intSeq. Quoi qu'il en soit, vous pouvez utiliser std::integral_constant<IT, Val> au lieu de intSeq<IT, Val>.

0

Version courte et très lisible à l'aide 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