C ++: есть ли способ определить статический массив встроенный? - PullRequest
12 голосов
/ 05 февраля 2010

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

Использование:

int x;  // <- pretend this came from elsewhere...
if (isoneof(x, {5,3,9,25}) ...

Что-то вроде:

template <typename T, size_t size>
bool isoneof(T value, T (&arr)[size])
{
    for (size_t i = 0; i < size; ++i)
        if (value == arr[i])
            return true;
    return false;
}

Я предполагаю, что это обречено на провал, так как я не понимаю, как можно создать статический массив встроенным.

Я могу использовать:

int kPossibilities[] = {5,3,9,25};
if (isoneodf(6, kPossibilities)) ...

С незначительным изменением на isoneof :

template <typename T1, typename T2, size_t size>
bool isoneof(T1 value, const T2 (&arr)[size])
{
    for (size_t i = 0; i < size; ++i)
        if (value == arr[i])
            return true;
    return false;
}

Что также делает его более гибким.

Кто-нибудь может предложить улучшение? Лучший способ определить «набор встроенных статических значений» ?

Ответы [ 6 ]

12 голосов
/ 05 февраля 2010

Если вам нравятся такие вещи, то вы будете очень счастливым пользователем Boost.Assign .

Boost.Assign фактически доказывает, что такая семантика возможна , однако один взгляд на источник назначения убедит вас, что вы не хотите делать это самостоятельно:)

Вы сможете создать что-то вроде этого, однако:

if (isoneof(x, list_of(2)(3)(5)(7)(11)) { ...

... недостатком является то, что вам придется использовать boost::array в качестве параметра вместо встроенного массива (спасибо, Мануэль) - однако, это хороший момент, чтобы фактически начать их использовать:>

5 голосов
/ 05 февраля 2010

Это возможно в следующем стандарте C ++.

До этого вы можете обойти это, например, перегрузка operator, для статического объекта, который запускает статический массив.

Примечание: эта реализация O (n ^ 2) и может быть оптимизирована - это просто идея.

using namespace std;

template< typename T, size_t N > 
struct CHead {
    T values[N];
    template< typename T > CHead<T,N+1> operator,( T t ) { 
      CHead<T,N+1> newhead;
      copy( values, values+N, newhead.values);
      newhead.values[N]=t;
      return newhead;
    }
    bool contains( T t ) const { 
       return find( values, values+N, t ) != values+N; 
    }
};

struct CHeadProto {
  template< typename T > 
  CHead<T,1> operator,( T t ) { 
     CHead<T,1> h = {t}; 
     return h; 
  }
} head;



int main()
{
  assert( (head, 1,2,3,4).contains(1) );
  return 0;
}
2 голосов
/ 06 февраля 2010

Ради полноты я выложу решение, которое использует Boost.MPL. Следующее работает, но я думаю, что решение Корнеля является лучшим.

#include <iostream>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/vector_c.hpp>

struct Contains
{
    Contains(int value, bool& result) : value(value), result(result)
    {
        result = false;
    }

    template< typename T > void operator()(T x)
    {
        result = result || (x == value);
    }

    int value;
    bool& result;
};


template <class IntList>
bool isoneof(int val)
{
    namespace mpl = boost::mpl;
    bool result;
    mpl::for_each<IntList>(Contains(val, result));
    return result;
}


int main()
{
    namespace mpl = boost::mpl;
    std::cout << isoneof< mpl::vector_c<int, 1,2,3,5,7,11> >(4) << "\n";
    std::cout << isoneof< mpl::vector_c<int, 1,2,3,5,7,11> >(5) << "\n";
}

Как видите, массив времени компиляции передается в виде аргумента шаблона в isoneof.

1 голос
/ 02 июля 2013

Используя C ++ 11, это было бы написано так:

template <typename T>
bool isoneof(T value, std::initializer_list<T> arr)
{
    using namespace std;

    return any_of(begin(arr), end(arr), [&](const T& x) { return x == value; });
}
1 голос
/ 05 февраля 2010

Этот?

int ints[] = {2,3,5,7,11};
#define ARRAY_SIZE(Array) (sizeof(Array)/sizeof((Array)[0]))
#define INLIST(x,array) isoneof(x,array,ARRAY_SIZE(array))

Сложение:

template <typename T>
bool isoneof(const T& x, T *array, int n)
{
        for(int i=0; i<n; ++i)
                if(x==array[i])
                        return true;
        return false;
}
0 голосов
/ 05 марта 2018

Только к вашему сведению - я решил свою конкретную проблему с помощью шаблонов vararg и списков инициализаторов теперь, когда у меня есть доступ к C ++ 14:

template <typename T, typename U>
bool isoneof(T v, U v1) { return v == v1; }

template <typename T, typename U, typename... Args>
bool isoneof(T v, U v1, Args ... others) { return isoneof(v, v1) || isoneof(v, others...); }

template <typename T, typename U>
bool isoneof(T value, std::initializer_list<U> values)
{
    for (const auto & e : values)
        if (value == e)
            return true;
    return false;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...