21

我在C++编码,我有以下代码:

int array[30];
array[9] = 1;
array[5] = 1;
array[14] = 1;

array[8] = 2;
array[15] = 2;
array[23] = 2;
array[12] = 2;
//...

有没有办法初始化类似于以下的数组?

int array[30];
array[9,5,14] = 1;
array[8,15,23,12] = 2;
//...

注意:在实际代码中,最多可以有 30 个 slot 需要设置为一个值。

4

10 回答 10

32

此功能将有助于减轻疼痛。

void initialize(int * arr, std::initializer_list<std::size_t> list, int value) {
    for (auto i : list) {
        arr[i] = value;
    }
}

像这样称呼它。

initialize(array,{9,5,14},2);
于 2013-10-04T00:45:00.807 回答
9

aaronman 回答的一个变体:

template <typename T>
void initialize(T array[], const T& value)
{
}

template <size_t index, size_t... indices, typename T>
void initialize(T array[], const T& value)
{
    array[index] = value;
    initialize<indices...>(array, value);
}

int main()
{
    int array[10];

    initialize<0,3,6>(array, 99);

    std::cout << array[0] << " " << array[3] << " " << array[6] << std::endl;
}

示例:点击这里

于 2013-10-04T01:11:03.000 回答
7

只是为了好玩,我创建了一种稍微不同的方法,它需要一些允许初始化的基础设施,如下所示:

double array[40] = {};
"9 5 14"_idx(array) = 1;
"8 15 23 12"_idx(array) = 2;

如果数字需要用逗号分隔,则需要稍作改动。无论如何,这是完整的代码:

#include <algorithm>
#include <iostream>
#include <sstream>
#include <iterator>

template <int Size, typename T = int>
class assign
{
    int  d_indices[Size];
    int* d_end;
    T*   d_array;
    void operator=(assign const&) = delete;
public:
    assign(char const* base, std::size_t n)
        : d_end(std::copy(std::istream_iterator<int>(
                      std::istringstream(std::string(base, n)) >> std::skipws),
                          std::istream_iterator<int>(), this->d_indices))
        , d_array()
    {
    }
    assign(assign<Size>* as, T* a)
        : d_end(std::copy(as->begin(), as->end(), this->d_indices))
        , d_array(a) {
    }
    assign(assign const& o)
        : d_end(std::copy(o.begin(), o.end(), this->d_indices))
        , d_array(o.d_array)
    {
    }
    int const* begin() const { return this->d_indices; }
    int const* end() const   { return this->d_end; }
    template <typename A>
    assign<Size, A> operator()(A* array) {
        return assign<Size, A>(this, array);
    }
    void operator=(T const& value) {
        for (auto it(this->begin()), end(this->end()); it != end; ++it) {
            d_array[*it] = value;
        }
    }
};

assign<30> operator""_idx(char const* base, std::size_t n)
{
    return assign<30>(base, n);
}

int main()
{
    double array[40] = {};
    "1 3 5"_idx(array) = 17;
    "4 18 7"_idx(array) = 19;
    std::copy(std::begin(array), std::end(array),
              std::ostream_iterator<double>(std::cout, " "));
    std::cout << "\n";
}
于 2013-10-04T01:19:40.027 回答
5

为了好玩/实验,我只是玩了一下(请注意我在答案底部的担忧):

它是这样使用的:

smartAssign(array)[0][8]       = 1;
smartAssign(array)[1][4][2]    = 2;
smartAssign(array)[3]          = 3;
smartAssign(array)[5][9][6][7] = 4;

源代码:

#include <assert.h> //Needed to test variables
#include <iostream>
#include <cstddef>

template <class ArrayPtr, class Value>
class SmartAssign
{
    ArrayPtr m_array;

public:
    class Proxy
    {
        ArrayPtr m_array;
        size_t m_index;
        Proxy* m_prev;

        Proxy(ArrayPtr array, size_t index)
            : m_array(array)
            , m_index(index)
            , m_prev(nullptr)
        { }

        Proxy(Proxy* prev, size_t index)
            : m_array(prev->m_array)
            , m_index(index)
            , m_prev(prev)
        { }

        void assign(Value value)
        {
            m_array[m_index] = value;            
            for (auto prev = m_prev; prev; prev = prev->m_prev) {
                m_array[prev->m_index] = value;
            }
        }

    public:
        void operator=(Value value)
        {
            assign(value);
        }

        Proxy operator[](size_t index)
        {
          return Proxy{this, index};
        }

        friend class SmartAssign;
    };

    SmartAssign(ArrayPtr array)
        : m_array(array)
    {
    }


    Proxy operator[](size_t index)
    {
        return Proxy{m_array, index};
    }
};

template <class T>
SmartAssign<T*, T> smartAssign(T* array)
{
    return SmartAssign<T*, T>(array);
}

int main()
{
    int array[10];

    smartAssign(array)[0][8]       = 1;
    smartAssign(array)[1][4][2]    = 2;
    smartAssign(array)[3]          = 3;
    smartAssign(array)[5][9][6][7] = 4;

    for (auto i : array) {
        std::cout << i << "\n";
    }

    //Now to test the variables
    assert(array[0] == 1 && array[8] == 1);
    assert(array[1] == 2 && array[4] == 2 && array[2] == 2);
    assert(array[3] == 3);
    assert(array[5] == 4 && array[9] == 4 && array[6] == 4 && array[7] == 4);
}

让我知道你的想法,我通常不会写太多这样的代码,我相信有人会在某处指出一些问题;)

我不是 100% 确定代理对象的生命周期。

于 2013-10-04T02:02:55.717 回答
2

如果您的索引不相关,您可以做的最好的事情是“链接”分配:

array[9] = array[5] = array[14] = 1;

但是,如果您有某种方法可以确定性地计算索引,则可以使用循环:

for (size_t i = 0; i < 3; ++i)
    array[transform_into_index(i)] = 1;

如果您有一些存储索引的容器,则最后一个示例显然也适用。所以你可以做这样的事情:

const std::vector<size_t> indexes = { 9, 5, 14 };
for (auto i: indexes)
    array[i] = 1;
于 2013-10-04T00:42:25.210 回答
2

仍然不支持可变参数模板参数通用初始化列表的编译器,意识到某些已发布的解决方案将不起作用可能会很痛苦

看起来,OP 只打算处理数字数组,valarray使用可变参数实际上可以很容易地解决这个问题。

#include <valarray>     
#include <cstdarg>
#include <iostream>
#include <algorithm>
#include <iterator>
template <std::size_t size >
std::valarray<std::size_t>  selection( ... )
{
    va_list arguments; 
    std::valarray<std::size_t> sel(size);   
    //Skip the first element
    va_start ( arguments, size );
    va_arg ( arguments, int );
    for(auto &elem : sel)
        elem = va_arg ( arguments, int );
    va_end ( arguments );
    return sel;

}
int main ()
{
    //Create an array of 30 integers
    std::valarray<int> array(30);
    //The first argument is the count of indexes
    //followed by the indexes of the array to initialize
    array[selection<3>(9,5,14)] = 1;
    array[selection<4>(8,15,13, 12)] = 2;
    std::copy(std::begin(array), std::end(array),
              std::ostream_iterator<int>(std::cout, " "));
    return 0;
}
于 2013-10-04T07:00:46.083 回答
1

我记得,对于静态初始化,存在如下语法:

int array[30] = {
  [9] = 1, [8] = 2
}

等等。这适用于 gcc,关于另一个编译器 - 我不知道。

于 2013-10-04T00:43:37.770 回答
1

使用重载运算符 << 。

#include <iostream>
#include <iomanip>
#include <cmath>

// value and indexes wrapper
template< typename T,  std::size_t ... Ints> struct _s{ T value; };

//deduced value type
template< std::size_t ... Ints,  typename T>
constexpr inline   _s<T, Ints... >  _ ( T const& v )noexcept { return {v}; }


// stored array reference
template< typename T, std::size_t N>
struct _ref
{
    using array_ref = T (&)[N];

    array_ref ref;
};


//join _s and _ref with << operator.
template< 
        template< typename , std::size_t ... > class IC, 
        typename U, std::size_t N, std::size_t ... indexes
        >
constexpr _ref<U,N> operator << (_ref<U,N> r, IC<U, indexes...> ic ) noexcept
{
    using list = bool[];
    return (  (void)list{ false, (  (void)(r.ref[indexes] = ic.value), false) ... }) , r ;

    //return r;
}


//helper function, for creating _ref<T,N> from array.
template< typename T, std::size_t N>
constexpr inline _ref<T,N> _i(T (&array)[N] ) noexcept { return {array}; }



int main()
{

   int a[15] = {0};

   _i(a) << _<0,3,4,5>(7) << _<8,9, 14>( 6 ) ;


   for(auto x : a)std::cout << x << "  " ;  
   //       0  1  2  3  4  5  6  7  8  9 10 11 12 13 14
  //result: 7  0  0  7  7  7  0  0  6  6  0  0  0  0  6


  double b[101]{0};

  _i(b) << _<0,10,20,30,40,50,60,70,80,90>(3.14) 
        << _<11,21,22,23,24,25>(2.71) 
        << _<5,15,25,45,95>(1.414) ;
}
于 2013-10-04T09:34:21.287 回答
1
struct _i_t
{
    int * array;


    struct s
    {
        int* array;
        std::initializer_list<int> l;

        s const&   operator = (int value) const noexcept
        {
            for(auto i : l )
              array[i] = value;

            return *this;
        }
    };

    s operator []( std::initializer_list<int> i ) const noexcept
    {
        return s{array, i};
    }
};

template< std::size_t N>
constexpr _i_t   _i( int(&array)[N]) noexcept { return {array}; }

int main()
{
  int a[15] = {0};
  _i(a)[{1,3,5,7,9}] =  7;

  for(auto x : a)std::cout << x << ' ';


}
于 2013-10-04T14:16:26.037 回答
0

您所做的任何花哨的技巧都会被编译器/汇编器展开成您所拥有的。你这样做是出于可读性的原因吗?如果您的数组已经初始化,您可以执行以下操作:

array[8] = array[15] = array[23] = array[12] = 2;

但我在上面强调我的观点;它会变成你所拥有的。

于 2013-10-04T00:44:44.883 回答