С++: Есть ли способ определить статический массив inline?

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

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

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

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

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

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

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

Есть ли у кого улучшения? Лучший способ определить "набор статических значений inline" ?

Ответ 1

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

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

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

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

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

Ответ 2

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

До тех пор вы можете обойти это, например. перегрузка 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;
}

Ответ 3

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

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

Как вы можете видеть, массив compile-time передается inline в качестве аргумента шаблона в isoneof.

Ответ 4

Этот?

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

Ответ 5

Используя С++ 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; });
}