Mordachai
Mordachai

Reputation: 9662

C++: Is there a way to define a static array inline?

I would like to define a simple template function which takes a runtime value and determines if it is a member of some set of possible values.

Usage:

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

Something like:

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

I assume that this is doomed to failure, as I don't see how one can create a static array inline.

I can use:

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

With a minor change to 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;
}

Which also makes it a tad more flexible.

Does anyone have an improvement to offer? A better way to define a "set of static values inline"?

Upvotes: 12

Views: 4350

Answers (6)

Mordachai
Mordachai

Reputation: 9662

Just FYI - I solved my particular problem using vararg templates and initializer lists now that I have access to 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;
}

Upvotes: 0

Laurent LA RIZZA
Laurent LA RIZZA

Reputation: 2965

Using C++11, this would be written like this:

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

Upvotes: 1

Emile Cormier
Emile Cormier

Reputation: 29209

For the sake of completeness, I'll post a solution that uses Boost.MPL. The following works, but I think Kornel's solution is best.

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

As you can see, the compile-time array is passed inline as a template argument to isoneof.

Upvotes: 2

Kornel Kisielewicz
Kornel Kisielewicz

Reputation: 57555

If you like such things, then you will be a very happy user of Boost.Assign.

Boost.Assign actually proves that such semantics are possible, however one look at the source of assign will convince you that you don't want to do that by yourself :)

You will be able to create something like this however:

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

... the downside being you'd have to use boost::array as the parameter instead of a built-in array (thanks, Manuel) -- however, that's a nice moment to actually start using them :>

Upvotes: 12

xtofl
xtofl

Reputation: 41509

It's possible in the next C++ standard.

Up till then, you can work around it by e.g. overloading operator, for a static object that starts a static array.

Note: this implementation is O(n^2) and may be optimized - it's just to get the idea.

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

Upvotes: 5

Notinlist
Notinlist

Reputation: 16640

This one?

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

ADDITION:

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

Upvotes: 1

Related Questions